必须开启innodb_stats_persistent=ON确保统计信息重启不丢失,否则执行计划易突变;需配合关闭自动重算、调高采样页数并定期ANALYZE TABLE以保障统计准确性和执行计划稳定性。

执行计划本身不能持久化,真正起作用的是统计信息的持久化——MySQL 8.0 的 innodb_stats_persistent=ON 保证了表行数、索引基数(Cardinality)、列分布等关键统计不随重启丢失,优化器每次生成执行计划时都有稳定输入,从而大幅降低索引选择突变概率。
为什么重启后执行计划会抖?
根本原因是统计信息重置:MySQL 默认在重启时丢弃内存中的统计,重新采样。若采样不准或未触发自动更新,优化器就会误判索引价值。
-
INNODB_TABLESTATS.last_update时间戳归零或回退到旧时间,导致EXPLAIN中rows严重失真(比如显示 100 行,实际扫描 50 万行) - 小表(如配置表)因数据量少,采样页数
innodb_stats_persistent_sample_pages=20不够,Cardinality被低估,优化器放弃走索引 - 大表(如订单表)若长期未
ANALYZE TABLE,而innodb_stats_auto_recalc=ON又因变更未超 10% 不触发,统计就“冻住”在升级前或上线初期
如何验证统计是否真正持久化?
不能只看默认值,必须查运行时状态和元数据:
- 执行
SHOW VARIABLES LIKE 'innodb_stats_persistent';,确认返回值是ON(不是OFF或空) - 查
SELECT last_update FROM INFORMATION_SCHEMA.INNODB_TABLESTATS WHERE TABLE_NAME = 'orders';,确保时间戳在最近一次ANALYZE TABLE后,且不早于服务启动时间 - 对比
SHOW INDEX FROM orders;中Cardinality和SELECT COUNT(DISTINCT status) FROM orders;,若差距 > 5 倍,说明采样仍不准,需调高innodb_stats_persistent_sample_pages
为什么光开 innodb_stats_persistent 还不够?
持久化只是“存得住”,不等于“算得准”或“用得稳”:
-
innodb_stats_auto_recalc=ON在高频小表上会频繁重算,拖慢后台线程,还可能因并发采样冲突导致统计滞后;建议全局关掉,改用定时ANALYZE TABLE - 默认采样页数
20对千万级表完全不够,尤其字段分布倾斜(如status只有 3 个值),应设为100~200并验证Cardinality - 直方图(
ANALYZE TABLE orders UPDATE HISTOGRAM ON status;)比调采样页更可靠,但仅补充列分布,不替代ANALYZE TABLE更新表级统计
真正容易被忽略的是:ANALYZE TABLE 是一次性快照,不是永久保质——批量导入、逻辑删除、历史归档后必须重新执行,否则统计就变成“过期地图”,再持久也没用。


















