优先执行analyze table,但必须先确认统计信息真过旧:explain的rows预估与实际行数偏差超10倍,或show index的cardinality与count(distinct col)相差百倍/为0/1,并排除函数、隐式转换、force index等干扰。

直接结论:优先执行 ANALYZE TABLE,但必须先确认真是统计过旧,而不是函数、隐式转换或索引设计本身的问题。
怎么判断真是统计信息过旧,不是其他原因?
别一看到 EXPLAIN 里 key 是 NULL 或 type: ALL 就跑 ANALYZE TABLE。先交叉验证两组数据:
- 查
EXPLAIN的rows预估 vs 实际返回行数:差 10 倍以上(比如预估 800 万,实际只 500 行)是强信号 - 查
SHOW INDEX FROM table_name中的CARDINALITYvs 真实去重数:SELECT COUNT(DISTINCT col) FROM table_name,如果前者是后者的 1/100 或直接为 0/1,基本坐实 - 排除干扰项:
WHERE DATE(log_dt) = ...这类函数用法、city_id = '565'字符串传整型、FORCE INDEX硬编码覆盖——这些情况下ANALYZE TABLE完全无效
ANALYZE TABLE 执行时容易踩哪些坑?
它不是“刷新缓存”,而是重新采样索引页并重算基数,操作不当反而白忙:
- 默认只采样约 20 个页,对大表或数据倾斜严重(比如
status字段 99% 是 1)极易失真;可临时调高:SET GLOBAL innodb_stats_persistent_sample_pages = 100 - 加的是表级读锁,大表执行期间会阻塞
DROP TABLE、ALTER TABLE和写入,务必避开高峰期 - 对分区表,默认不分析具体分区数据页,必须显式指定:
ANALYZE TABLE t PARTITION(p2024) - 如果
innodb_stats_persistent = OFF(MySQL 5.7 及以前默认关),统计只存在内存,重启或自动更新后立刻回退
为什么 ANALYZE TABLE 执行完,EXPLAIN 还是没换索引?
不是命令没跑,而是优化器根本没“看见”新统计,或被更高优先级规则压过了:
- 查
information_schema.STATISTICS表,确认CARDINALITY字段值确实变了,不只是STATS_INITIALIZED时间戳更新 - 检查 SQL 里有没有
FORCE INDEX或USE INDEX,它们会完全绕过优化器决策 - 是否存在更优的覆盖索引?比如查询
WHERE a = ? AND b > ?,优化器可能放弃你期待的idx_a,转而选idx_a_b复合索引——这不是错,是更合理 -
ANALYZE TABLE不修复索引结构问题,也不解决谓词条件导致的选择性误判(如b > ?范围过大时,即使统计准,优化器也可能弃用idx_a_b)
统计不准这事从不报错、不告警,安静地拖垮性能。真正要命的是:你查 EXPLAIN 时看到 key 字段有值,就以为索引还在工作,其实优化器早因基数崩了悄悄弃用——这个细节最容易被忽略。











