analyze table会触发mysql重新采样索引页并更新统计信息,具体包括:对innodb表随机采样默认20个叶子页估算cardinality等值并写入mysql.innodb_table_stats等系统表,不重建索引、不刷新缓存、不修改数据;对myisam表则全表扫描生成精确统计;执行时加mdl读锁,阻塞ddl但允许dml。

ANALYZE TABLE 会触发什么操作?
ANALYZE TABLE 不是简单地“刷新缓存”,它会让 MySQL 重新采样数据页,估算每个索引的基数(cardinality),更新 information_schema.STATISTICS 和存储引擎内部的统计结构。InnoDB 表默认只采样少量页面(由 innodb_stats_sample_pages 控制,默认 20),所以结果是近似值,不是精确统计。
- 对于 MyISAM 表,
ANALYZE TABLE会直接扫描全表并计算精确的键分布 - 对于 InnoDB 表,它基于随机采样估算,因此多次执行可能得到略有差异的
cardinality值 - 执行期间会对表加读锁(MDL lock),但不会阻塞 DML,只短暂阻塞 DDL
- 如果表正在被大量写入,采样结果可能滞后于实际数据分布
什么时候必须手动执行 ANALYZE TABLE?
优化器依赖统计信息生成执行计划,当以下情况出现时,手动触发往往比等自动更新更可靠:
- 批量导入或删除了超过 10% 的行(例如用
LOAD DATA INFILE或DELETE FROM ... WHERE) - 添加、删除或重建了索引后(尤其在测试环境快速验证索引有效性时)
- 发现某条查询突然变慢,且
EXPLAIN显示走了错误索引,而SHOW INDEX FROM tbl中对应索引的Cardinality明显异常(比如为 1 或远低于实际唯一值数量) - 升级 MySQL 版本后,旧统计信息格式不兼容,部分版本会自动失效
ANALYZE TABLE 的常见误操作和坑
ANALYZE TABLE 看似简单,但几个细节容易引发意外:
- 不支持通配符或正则:不能写
ANALYZE TABLE mydb.*,必须指定具体表名,批量操作需配合脚本生成语句 - 在只读实例上执行会报错:
ERROR 1786 (HY000): Statement violates GTID consistency(开启 GTID 且enforce_gtid_consistency=ON时) - 如果表使用压缩页(
ROW_FORMAT=COMPRESSED),采样可能失败并警告,此时需检查innodb_stats_method是否为NULLS_EQUAL(默认值,对 NULL 多的列易偏差) - 并发执行多个
ANALYZE TABLE不会串行排队,而是各自独立采样,可能导致短时间内统计值抖动 - 对大表执行耗时明显,可通过
SHOW PROCESSLIST观察状态为analyzing index key,而非updating status
替代方案与补充建议
ANALYZE TABLE 是最直接的方式,但不是唯一手段:
- 设置
innodb_stats_auto_recalc = ON(默认开启),可在表变更超 10% 时自动触发采样,但有延迟,且仅适用于 InnoDB - 用
INFORMATION_SCHEMA.STATISTICS查看当前统计:SELECT TABLE_NAME, INDEX_NAME, CARDINALITY FROM INFORMATION_SCHEMA.STATISTICS WHERE TABLE_SCHEMA = 'mydb' AND TABLE_NAME = 't1';
- 对关键大表,可临时调高采样页数提升精度:
SET GLOBAL innodb_stats_sample_pages = 100;,但会增加ANALYZE耗时 - 避免在业务高峰执行;若需定期维护,建议结合
pt-upgrade或自定义脚本,在低峰时段遍历information_schema.TABLES过滤出变动频繁的表
真正影响查询性能的,往往不是“有没有执行过 ANALYZE TABLE”,而是执行时机是否匹配数据变化节奏,以及采样参数是否适配你的数据倾斜特征。











