关闭innodb_stats_on_metadata可避免元数据查询触发的随机采样和统计更新,防止缓冲池污染与执行计划抖动,且不影响统计准确性;其仅禁用非必要自动更新路径,统计仍通过持久化机制或手动analyze table保持精准。

为什么高频自动统计会破坏执行计划稳定性
当 `innodb_stats_on_metadata=ON`(旧版本默认),每次执行以下任一操作,InnoDB 都会随机采样索引页、重建统计信息:
- SHOW TABLE STATUS 或 SHOW INDEX
- 查询 INFORMATION_SCHEMA.TABLES / STATISTICS / PARTITIONS 等视图
- 某些运维脚本、监控工具、ORM 的 introspection 行为(如 Django 的
./manage.py dbshell后查表结构)
这些操作本身不涉及业务逻辑,却可能在高并发时段触发大量 I/O 和 buffer pool 污染,导致统计值瞬时漂移。优化器基于新统计生成的执行计划可能突然走错索引或改用全表扫描——而你并未修改数据或结构。
关闭后,统计信息还准吗?
完全准确。因为:
- 统计信息仍会通过 持久化机制 自动更新:当表中约 10% 数据变更(由
innodb_stats_auto_recalc=ON控制)时,InnoDB 会重新采样并写入磁盘(mysql.innodb_table_stats和mysql.innodb_index_stats) - 你仍可随时手动运行
ANALYZE TABLE t1;主动刷新,且该操作可控、可调度、不影响业务峰值 - 关闭 `innodb_stats_on_metadata` 仅禁用「元数据查询附带更新」这一副作用,不干扰其他合法更新通道
正确关闭与验证步骤
适用 MySQL 5.5–5.7 及部分 Percona Server 版本(MySQL 5.6.6+ 默认已 OFF,但仍建议确认):
- 登录数据库,执行:
SET GLOBAL innodb_stats_on_metadata = OFF; - 立即验证生效:
SHOW GLOBAL VARIABLES LIKE 'innodb_stats_on_metadata'; → 应返回OFF - (可选)写入配置文件永久生效(重启不丢失):
在my.cnf的[mysqld]段添加:
innodb_stats_on_metadata = OFF - 观察效果:对比关闭前后执行
SELECT COUNT(*) FROM information_schema.TABLES WHERE TABLE_SCHEMA='your_db';的耗时,通常提升 2 倍以上,尤其在数百张表的库中更明显
配套建议:让统计真正稳下来
单关 `innodb_stats_on_metadata` 不够,还需组合配置:
- 启用持久化统计:innodb_stats_persistent = ON(5.6.6+ 默认开启),确保统计落地磁盘,重启不失效
- 控制自动更新粒度:innodb_stats_auto_recalc = ON(默认),配合合理采样页数(如
innodb_stats_persistent_sample_pages = 100对大表更准) - 禁用非必要自动更新(Percona):innodb_stats_on_metadata = OFF + innodb_stats_auto_update = OFF(若使用 Percona Server)
- 定期维护:在低峰期安排
ANALYZE TABLE或批量分析脚本,替代不可控的隐式更新











