innodb_stats_persistent必须为on,mysql 8.0默认启用但需确认;若为off需set persist开启;同时应合理配置innodb_stats_auto_recalc、innodb_stats_persistent_sample_pages及直方图以保障执行计划稳定。

innodb_stats_persistent 必须为 ON
MySQL 8.0 默认已启用 innodb_stats_persistent=ON,但生产环境务必确认。如果关闭,每次重启后统计信息重采样,执行计划可能突变——比如原本走 idx_order_time 的查询,重启后突然改走全表扫描。
检查命令: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 会在表数据变更超 10% 时触发后台统计更新,听起来合理,但实际容易误判——比如一个 1 亿行的订单表,单日增量 50 万(仅 0.5%),它不更新;而一个 10 万行的配置表,一天删增 2 万次(20%),它却反复重算,拖慢性能。
更稳妥的做法是按表分级控制:
- 对高频写入+低频查询的冷表,关掉自动更新:
ALTER TABLE config_cache STATS_AUTO_RECALC=0; - 对核心业务热表(如
orders),保留自动更新,或设为1(显式开启) - 所有表统一关掉自动更新后,改用定时任务在低峰期跑
ANALYZE TABLE orders, users;
提升采样精度:innodb_stats_persistent_sample_pages
默认值 20 对小表够用,但对千万级以上表,采样页太少会导致基数(cardinality)严重低估,优化器误判索引价值。例如性别字段明明只有两个值,统计却显示“分布均匀”,结果放弃使用索引。
调整建议:
- 中等规模表(100 万–500 万行):设为
50~100 - 大型热表(千万行以上):设为
100~200,但需观察ANALYZE TABLE耗时是否超 30 秒 - 修改方式:全局设
SET PERSIST innodb_stats_persistent_sample_pages = 100;,或单表指定ALTER TABLE orders STATS_SAMPLE_PAGES=200; - 切忌盲目拉到 500+——采样页翻倍,
ANALYZE时间可能翻 3 倍,且对 SSD I/O 压力明显
直方图补救数据倾斜:UPDATE HISTOGRAM
当字段存在严重值倾斜(如 95% 订单状态是 'paid',仅 5% 是 'shipped'),即使统计信息准确,优化器仍可能选错索引。这时直方图是唯一解法。
操作要点:
- 只对真正有倾斜的列建直方图,比如
status、region_id,别给主键或唯一索引列建 - 语法:
ANALYZE TABLE orders UPDATE HISTOGRAM ON status WITH 16 BUCKETS;(16是常用起点,最多 1024) - 直方图不自动更新,数据分布变化大时需重新执行该语句
- 查看是否生效:
SELECT * FROM information_schema.COLUMN_STATISTICS WHERE TABLE_NAME = 'orders';
直方图不是银弹——它只影响等值查询(=、IN)和范围查询(BETWEEN)的选择性估算,对 LIKE '%abc' 无效。而且一旦建了,就得持续维护,否则比没有还误导。











