真正需重建MySQL索引仅当基数严重失真或Data_free持续超25%且范围查询变慢;优先ANALYZE TABLE验证统计信息,避免盲目OPTIMIZE TABLE引发锁表雪崩。

重建MySQL索引不是“执行一条命令就完事”的操作,它直接关联表锁、磁盘IO、主从延迟和业务可用性。对大表或高并发表,盲目执行 OPTIMIZE TABLE 或 ALTER TABLE ... REBUILD 极易引发雪崩——你看到的慢查询,可能只是重建过程中的副产物。
什么时候真需要重建索引?
别把“索引碎片”当万能借口。InnoDB 的 B+ 树天然具备页合并能力,日常 DML 很少导致严重碎片。真正该重建的信号只有两个:
- 查
INFORMATION_SCHEMA.INNODB_SYS_INDEXES,发现某个索引的STATS_N_DIFFERENT(基数)严重偏离实际唯一值数量,且EXPLAIN显示该索引被跳过 - 用
SHOW TABLE STATUS查Data_free字段:对 InnoDB 表,若该值长期 > 表数据大小的 25%,且伴随明显范围查询变慢(非等值),才考虑干预 - MyISAM 表可直接看
Data_free+Rows比例,>30% 且Key_blocks_used / Key_blocks_unused失衡时再动
InnoDB 表重建必须绕开 OPTIMIZE TABLE
OPTIMIZE TABLE 在 InnoDB 中本质是 ALTER TABLE ... FORCE,会触发全表拷贝(COPY 模式),全程锁表。哪怕 MySQL 8.0,默认行为仍是阻塞写入——这不是“在线”,是“假在线”。
安全做法只有两条路:
- 用原生 Online DDL:
ALTER TABLE t1 ENGINE=InnoDB, ALGORITHM=INPLACE, LOCK=NONE;—— 必须确认 MySQL 版本 ≥ 5.6 且操作支持 INPLACE(比如仅重建索引不改结构) - 用
pt-online-schema-change:对超大表(>100GB)或无法停写场景,它通过触发器双写+原子切换,真正零锁表,但需额外磁盘空间和更长窗口期 - 绝对避开
OPTIMIZE TABLE和ALTER TABLE ... REBUILD(后者在 8.0+ 才支持,仍可能锁表)
重建前必须验证统计信息是否已过期
90% 的“索引失效”问题,根源是优化器用了过时的统计信息,而非物理碎片。先跑 ANALYZE TABLE t1;,再用 EXPLAIN 看执行计划是否改善——很多时候这一步就能省掉重建。
注意:ANALYZE TABLE 是轻量级操作,但默认采样率低(innodb_stats_sample_pages=20)。对倾斜数据分布的表,手动提高采样:
SET GLOBAL innodb_stats_sample_pages = 100; ANALYZE TABLE t1;
执行后检查 INFORMATION_SCHEMA.STATISTICS 中的 Cardinality 是否合理,再决定是否继续重建。
重建后的关键验证点
重建不是终点,而是风险暴露的开始。必须立刻验证三件事:
- 主从延迟:查
SHOW SLAVE STATUS\G的Seconds_Behind_Master,重建期间从库 SQL 线程可能积压数小时;如延迟突增,立即暂停后续操作 - 缓冲池命中率:监控
Innodb_buffer_pool_read_requests与Innodb_buffer_pool_reads比值,重建后若命中率骤降( - 慢查询回归:对比重建前后
slow_query_log中相同 SQL 的rows_examined和执行时间,防止新索引反而诱导优化器选错路径
最常被忽略的是:重建后索引的 B+ 树高度可能变化,导致原本稳定的等值查询突然变成范围扫描——这只能靠 EXPLAIN FORMAT=TREE 查看真实访问路径,而不是只信 key 字段是否非空。


















