analyze table是迁移后第一动作,因迁移工具导入数据后不会自动更新统计信息,导致优化器依赖的cardinality失真,索引虽存在却无法被选择;该操作开销小、不锁表、效果立竿见影。

直接执行 ANALYZE TABLE,90% 以上的“索引存在却不走索引”问题当场解决。
为什么 ANALYZE TABLE 是迁移后第一动作
迁移工具(如 mysqldump、DRS、LOAD DATA INFILE)导入数据时,不会自动触发统计信息收集。MySQL 优化器依赖 Cardinality 值判断索引选择性,而迁移后该值常为 0 或严重失真——导致明明有索引,EXPLAIN 却显示 type: ALL 和 key: NULL。
这不是索引丢了,是优化器“看不见”索引的价值。相比重建表或索引,ANALYZE TABLE 开销极小、不锁表(仅需元数据锁),且效果立竿见影。
- 对单表:运行
ANALYZE TABLE order_detail; - 对整库批量生成语句:
SELECT CONCAT('ANALYZE TABLE ', table_schema, '.', table_name, ';') FROM information_schema.tables WHERE table_schema = 'your_db';,复制结果执行 - 执行后立刻用
EXPLAIN SELECT * FROM order_detail WHERE user_id = 123;验证,key字段应出现索引名,rows显著下降
ANALYZE TABLE 不生效的几种典型情况
如果执行后 EXPLAIN 仍不走索引,别急着重建,先检查这些硬性条件:
-
SHOW INDEX FROM order_detail;中目标列的Cardinality仍是 0 —— 说明表为空或刚被截断,需确认数据是否真正写入 - 索引定义异常:
SHOW CREATE TABLE order_detail;查看是否有VARCHAR列带前缀(如title(191)),跨字符集迁移(utf8 → utf8mb4)后可能被静默降级失效 - WHERE 条件字段存在隐式类型转换,比如查询字段是
INT,但传入字符串'123',导致索引失效 —— 这和统计信息无关,得改 SQL 或字段类型 - 使用了函数或表达式:
WHERE DATE(create_time) = '2026-01-01'会跳过索引,需改用范围查询
何时才需要重建索引而非只分析
ANALYZE TABLE 解决的是“优化器不敢用索引”,重建索引解决的是“索引本身不可用”。只有当确认以下任一情况存在时,才考虑重建:
-
SHOW CREATE TABLE里缺失关键索引定义(比如UNIQUE KEY没了),说明迁移过程漏建 - 跨字符集迁移后,原
VARCHAR(255)索引因超 767 字节限制被自动截断,需显式重建并指定前缀长度:CREATE INDEX idx_user_email ON users(email(191)) ALGORITHM=INPLACE; - 索引碎片严重且数据量极大(>1TB),
ANALYZE TABLE后EXPLAIN的rows仍远高于实际匹配行数 —— 此时可配合OPTIMIZE TABLE,但注意它会锁表
生产环境执行的两个关键提醒
别在高峰期跑全库 ANALYZE TABLE,尤其当表特别多时,虽然单表轻量,但并发扫描仍可能推高 I/O;更隐蔽的风险是:如果启用了 innodb_stats_persistent = OFF(MySQL 5.6 默认),统计信息可能在下次重启后再次丢失 —— 建议设为 ON 并配合适当的采样页数(innodb_stats_persistent_sample_pages)。











