analyze table 有时没效果,是因为它只更新优化器使用的统计信息,不刷新 information_schema 缓存(受 information_schema_stats_expiry 控制)、不持久化(若 innodb_stats_persistent=off)、采样不足或未同步 auto_increment 等字段。

ANALYZE TABLE 能解决大部分索引信息不准的问题,但它不是万能的“刷新按钮”——它只更新统计信息,不改变 information_schema 缓存行为或元数据延迟。
为什么 ANALYZE TABLE 有时没效果?
执行完 ANALYZE TABLE t 后,EXPLAIN 显示的 rows 还是离谱,或者 information_schema.tables.table_rows 仍不更新,常见原因有:
-
information_schema表(如tables)在 MySQL 8.0+ 默认启用缓存,受information_schema_stats_expiry控制,默认值为86400(24 小时),即使刚ANALYZE,只要未过期,查询仍返回旧缓存值 -
ANALYZE TABLE不强制刷新auto_increment值、索引列基数(cardinality)等部分字段,这些可能仍滞后于实际状态 - 若表使用
innodb_stats_persistent=OFF(默认 OFF),统计信息只在内存中临时生效,重启后丢失,且不持久化到磁盘 -
ANALYZE TABLE采样页数不足(innodb_stats_sample_pages默认 20),对大表或数据倾斜严重的情况,估算误差可能仍很大
ANALYZE TABLE 和 information_schema_stats_expiry=0 必须配对用
想让 information_schema 查询(比如查 table_rows 或 avg_row_length)立刻反映最新状态,不能只靠 ANALYZE TABLE:
- 先设
SET GLOBAL information_schema_stats_expiry = 0:禁用缓存,每次查information_schema都实时计算 - 再执行
ANALYZE TABLE t:确保底层统计信息已更新 - 注意:该变量仅影响
information_schema查询,不影响优化器决策;优化器始终读取 InnoDB 数据字典里的统计信息(即ANALYZE写入的那部分)
哪些情况 ANALYZE TABLE 真正有用?
它主要修复的是优化器选错索引、误判行数导致走全表扫描这类问题,典型场景包括:
- 大批量
INSERT/DELETE后,EXPLAIN显示rows远低于实际扫描量(例如标称扫 100 行,实际扫 50 万行) - 联合索引选择性突变(如某列值突然大量重复),导致优化器放弃本该高效的索引
- 新建索引后,
EXPLAIN仍显示key=NULL,说明优化器还没“看到”新索引的统计价值 - 升级 MySQL 8.0 后首次运行老 SQL,因默认采样策略变化,统计偏差放大
容易被忽略的细节:ANALYZE TABLE 不等于“重建索引”
很多人以为它会像 OPTIMIZE TABLE 那样整理 B+ 树碎片、回收空间,其实完全不是:
-
ANALYZE TABLE只读取少量数据页,估算列分布、索引基数、表行数等元统计,不修改数据页物理结构 - 它不会降低
data_free,也不会减少index_length,更不会修复损坏的索引 - 如果怀疑索引本身逻辑异常(比如
SHOW INDEX显示的Cardinality为 0 但数据明显有区分度),优先检查是否innodb_stats_on_metadata=ON干扰了采样,而不是反复ANALYZE
ANALYZE”,而是没意识到 information_schema 的缓存和优化器用的统计信息根本是两套机制。改配置、清缓存、重采样,三步缺一不可。











