
ANALYZE TABLE 什么时候必须手动执行
MySQL 的统计信息不是实时更新的,尤其是大表在大量 INSERT/UPDATE/DELETE 后,EXPLAIN 显示的行数可能严重失真,导致优化器选错索引或走全表扫描。ANALYZE TABLE 就是主动触发统计信息重采样的命令,但它的触发时机很关键:
- 表数据量变化超过 10%~20%(InnoDB 默认阈值),且未开启
innodb_stats_auto_recalc=ON - 刚创建完索引,但后续没查过、也没触发自动采样
- 执行了
OPTIMIZE TABLE或ALTER TABLE ... ENGINE=InnoDB,这类操作不自动更新统计信息 - 发现某条查询的
EXPLAIN显示rows和实际扫描量差一个数量级,且排除了缓存干扰
ANALYZE TABLE 实际做了什么
它不是“刷新”整个统计系统,而是对指定表重新采样页和索引叶节点,估算:键值分布(cardinality)、索引深度、平均每页记录数等。这些数据存在 mysql.innodb_table_stats 和 mysql.innodb_index_stats 中(InnoDB)。
- 默认只采样 8 个叶子页(
innodb_stats_sample_pages=8),小表够用,大表容易不准 - 采样是随机的,所以两次
ANALYZE TABLE可能得出略有差异的 cardinality - 不会锁表(只加 MDL 读锁),但会短暂阻塞 DDL;对高并发写入表,建议在低峰执行
- MyISAM 表会直接遍历全部索引文件,更准但也更慢、更重
常见误用和踩坑点
很多人以为 ANALYZE TABLE 是“万能刷新”,结果发现执行后查询没变快,甚至更慢——问题往往出在以下几点:
系统功能强大、操作便捷并具有高度延续开发的内容与知识管理系统,并可集合系统强大的新闻、产品、下载、人才、留言、搜索引擎优化、等功能模块,为企业部门提供一个简单、易用、开放、可扩展的企业信息门户平台或电子商务运行平台。开发人员为脆弱页面专门设计了防刷新系统,自动阻止恶意访问和攻击;安全检查应用于每一处代码中,每个提交到系统查询语句中的变量都经过过滤,可自动屏蔽恶意攻击代码,从而全面防止SQL注入攻击
- 对分区表只执行
ANALYZE TABLE t,只更新一级分区元数据,不递归分析每个分区;应改用ANALYZE TABLE t PARTITION (p0, p1) - 在从库上执行,但主从复制延迟大时,统计信息可能立刻被主库的 DML 覆盖,白干
- 误以为它能修复索引损坏——不能,
CHECK TABLE和REPAIR TABLE才管这个 - 配合
innodb_stats_persistent=OFF使用时,重启 MySQL 后统计信息丢失,需重新ANALYZE - 使用
mysqldump --single-transaction导出期间执行ANALYZE,可能因 MVCC 快照不一致导致采样偏差
要不要调大采样页数
当表行数超千万、索引基数高(比如 UUID 前缀字段),默认 8 页采样常导致 cardinality 低估,优化器倾向用错索引。这时可以临时调高:
- 全局调整:
SET GLOBAL innodb_stats_sample_pages = 24(注意:仅影响后续新 ANALYZE,不回溯已有统计) - 单次增强:
ANALYZE TABLE t WITH N SAMPLES(MySQL 8.0.23+ 支持,N ≥ 16 更稳妥) - 但别无脑设到 100:采样页越多,
ANALYZE耗时越长,且边际收益下降;SSD 上 24~64 通常是性价比拐点 - 调完记得观察
SELECT * FROM mysql.innodb_index_stats WHERE table_name = 't'中stat_value是否更合理
统计信息本身不持久、不跨实例、不自动同步,靠的是采样逻辑和配置组合。最麻烦的其实是判断“该不该跑”——没有报错、没有日志提醒,只能靠你定期看 EXPLAIN 和慢查里的 rows 是否可信。









