MySQL 8.0中INFORMATION_SCHEMA查询变慢主因是优化器逻辑变更,不再视其为静态视图,而在JOIN或子查询时反复触发动态元数据扫描;危险写法包括IN子查询、无下推条件的JOIN及未过滤视图;有效解法为加/+ MATERIALIZE /提示或拆步执行。

为什么INFORMATION_SCHEMA查询在8.0里突然卡住
不是服务器变慢,也不是磁盘IO瓶颈,而是MySQL 8.0优化器对INFORMATION_SCHEMA表的处理逻辑变了:它不再把这类元数据表当“静态视图”看,而是在JOIN、子查询或WHERE条件不明确时,反复触发动态元数据扫描。哪怕INFORMATION_SCHEMA.TABLES只有几百行,EXPLAIN显示rows=1000,真实耗时可能从毫秒级跳到几秒——因为每次扫描都要重新打开表、校验权限、拼装内存临时结构。
哪些SQL写法在8.0里最危险
以下模式极易放大元数据扫描开销,升级后首当其冲:
-
SELECT * FROM t WHERE t.col IN (SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 't'):优化器倾向转成关联子查询,外层每行都查一遍COLUMNS -
SELECT c.* FROM INFORMATION_SCHEMA.COLUMNS c JOIN mydb.tables t ON c.table_name = t.name:8.0不会下推t.name条件,先全量生成所有列元数据再JOIN -
CREATE VIEW v AS SELECT * FROM INFORMATION_SCHEMA.STATISTICS; SELECT * FROM v WHERE table_schema = 'mydb':视图定义无过滤,8.0默认不合并也不下推,物化全部统计项再筛
立刻见效的两种干预方式
别碰ANALYZE TABLE INFORMATION_SCHEMA.*——它会报错或静默失败。真正能用的只有:
- 加
/*+ MATERIALIZE */提示强制物化子查询:SELECT * FROM t WHERE t.name IN (/*+ MATERIALIZE */ SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = 't') - 拆成两步:先用客户端执行
mysql -N -s -e "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name='t'" > cols.txt,再把结果拼进主SQL的IN列表
长期可用的配置级缓解
会话级缓存能压低重复查询延迟,但治标不治本:
- 执行
SET SESSION information_schema_stats_expiry = 86400,让元数据缓存24小时(单位秒) - 确认生效:
SHOW VARIABLES LIKE 'information_schema_stats_expiry',注意该变量不支持全局设置,必须每个连接单独设 - 配套动作:确保所有业务表已转
ENGINE=InnoDB,MyISAM表越多,8.0访问其元数据越慢
真正难绕开的是“动态生成”这个本质——只要SQL里带JOIN或非确定性条件,就可能触发重扫。所以最稳的写法,是尽量避免在业务逻辑中直接JOIN INFORMATION_SCHEMA表,改用预查+硬编码或定期导出的元数据快照。


















