监控脚本在mysql 8.0变慢是因优化器对information_schema表“误优化”,如select count(*) from information_schema.columns where table_schema='mydb'从秒级变为2~5秒,因where被延迟到物化后执行导致全量扫描。

为什么监控脚本在MySQL 8.0里突然变慢
不是脚本写错了,是INFORMATION_SCHEMA表在8.0里被优化器“误优化”了。比如原来SELECT COUNT(*) FROM INFORMATION_SCHEMA.COLUMNS WHERE table_schema = 'mydb'在5.7里秒出结果,8.0里可能卡住2~5秒——因为优化器把WHERE条件拖到物化之后才过滤,导致全量扫描所有库的列元数据。
哪些INFORMATION_SCHEMA用法必须改
以下模式在8.0中极易触发性能雪崩,需立即调整:
- 用
IN (SELECT ... FROM INFORMATION_SCHEMA.TABLES)做外层过滤:优化器倾向转成嵌套循环,每行都查一次TABLES -
JOIN其他业务表(如JOIN users u ON u.table_name = c.table_name):8.0不支持下推WHERE,先生成全部COLUMNS再关联 - 视图定义里直接引用
INFORMATION_SCHEMA.COLUMNS,再对外层加WHERE table_schema = 'xxx':8.0默认不合并也不下推,物化全部列后才筛
怎么改才不改逻辑只改性能
两种低成本修复方式,选一个就行:
- 加
/*+ MATERIALIZE */提示:把子查询强制物化,避免反复扫描。例如:SELECT * FROM t WHERE t.col 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_schema='mydb'" > cols.txt),再在脚本里读文件拼IN列表
别碰ANALYZE TABLE INFORMATION_SCHEMA.COLUMNS——它会报错或静默失败,INFORMATION_SCHEMA表没有传统统计信息。
容易被忽略的兼容性细节
升级后监控脚本跑得慢,往往不是SQL本身问题,而是隐含依赖变了:
-
EXPLAIN显示rows=1000不代表真扫1000行,INFORMATION_SCHEMA的rows只是占位符,实际开销看执行时间是否随库表数量线性增长 - 如果脚本里用了
DERIVED或DEPENDENT SUBQUERY节点(SHOW WARNINGS可看到重写后的SQL),基本就是性能黑洞源头 - 某些DBA工具(如pt-query-digest)解析慢日志时会自动展开INFORMATION_SCHEMA子查询,导致误判为“慢SQL”,其实瓶颈不在业务SQL而在元数据访问方式











