MySQL 8.0需确认innodb_stats_persistent=ON,否则重启后执行计划突变;应分级控制innodb_stats_auto_recalc,调大innodb_stats_persistent_sample_pages提升采样精度,并对倾斜列建直方图补救。

确认 innodb_stats_persistent 是否已启用
MySQL 8.0 默认开启 innodb_stats_persistent=ON,但生产环境必须验证——重启后执行计划突变(比如索引突然不走了)往往就源于它被意外关掉。
检查命令:SHOW VARIABLES LIKE 'innodb_stats_persistent';,返回值必须是 ON。若为 OFF,立即执行:SET PERSIST innodb_stats_persistent = ON;
SET PERSIST 会写入 mysqld-auto.cnf,比手动改 my.cnf 更可靠,且优先级更高;该参数不可动态关闭,设完就别动了。
按表控制自动更新:避免 innodb_stats_auto_recalc 误触发
innodb_stats_auto_recalc 默认 ON,规则是“单表数据变更超 10% 后异步触发 ANALYZE TABLE”。但这在真实业务中容易失准:
- 一个 1 亿行的订单表,日增 50 万(仅 0.5%),它不更新 → 统计滞后
- 一个 10 万行的配置表,一天反复删增 2 万次(累计 20%),它频繁重算 → 拖慢后台 I/O
更稳妥的做法是分级控制:
- 对高频写、低频查的冷表(如缓存表):
ALTER TABLE config_cache STATS_AUTO_RECALC = 0; - 对核心热表(如
orders):ALTER TABLE orders STATS_AUTO_RECALC = 1;或保留全局默认 - 统一关闭自动更新后,改用定时任务在低峰期跑:
ANALYZE TABLE orders, users;
调大 innodb_stats_persistent_sample_pages 提升采样精度
默认 innodb_stats_persistent_sample_pages = 20 对小表够用,但千万级表采样页太少,会导致基数(cardinality)严重低估。例如性别字段只有两个值,统计却显示“分布均匀”,优化器直接放弃索引。
调整建议:
- 100 万–500 万行表:
SET PERSIST innodb_stats_persistent_sample_pages = 100; - 千万行以上热表:
ALTER TABLE orders STATS_SAMPLE_PAGES = 200;(单表粒度更精准) - 切忌盲目拉到 500+ —— 采样页翻倍,
ANALYZE TABLE耗时可能翻 3 倍,SSD I/O 压力陡增
修改后观察 ANALYZE TABLE 执行时间是否超过 30 秒,再决定是否回调。
用 UPDATE HISTOGRAM 补救严重值倾斜
即使统计信息准确,遇到明显数据倾斜(如 95% 订单状态是 'paid',仅 5% 是 'shipped'),优化器仍可能选错索引。这时直方图是唯一解法。
操作要点:
- 只对真正有倾斜的列建直方图,比如
status、region_id - 别给主键或唯一索引列建(毫无意义)
- 建直方图命令:
ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 16 BUCKETS; - 直方图不会自动更新,需配合定期
ANALYZE TABLE ... UPDATE HISTOGRAM或在数据批量变更后手动触发
直方图生效依赖持久化统计开启,且只影响优化器对 WHERE 条件中该列的选择性估算——这是很多 DBA 忘记打开的“最后一道保险”。


















