MySQL不直接提供索引碎片率,但可通过SHOW TABLE STATUS查Data_free估算;若free_mb超size_mb的20%~30%且存在大量DELETE/UPDATE,则建议OPTIMIZE TABLE或ALTER TABLE ... REBUILD优化。

怎么查 MySQL 表的索引碎片率
MySQL 本身不直接暴露“碎片率”数值,但可以通过 INFORMATION_SCHEMA.INNODB_SYS_TABLESTATS 和 INFORMATION_SCHEMA.INNODB_SYS_INDEXES 配合估算。更实用的是查 DATA_FREE 和页利用率:
- 对 InnoDB 表,执行
SHOW TABLE STATUS LIKE 'your_table_name',关注Data_free字段(单位字节)——它表示已分配但未使用的空间,值越大越可能有碎片 - 用
SELECT table_name, round(((data_length + index_length) / 1024 / 1024), 2) AS size_mb, round((data_free / 1024 / 1024), 2) AS free_mb FROM information_schema.tables WHERE table_schema = 'your_db' AND table_name = 'your_table'; - 若
free_mb超过size_mb的 20%~30%,且表长期有大量 DELETE/UPDATE,就值得优化
OPTIMIZE TABLE 能不能重建索引
对 InnoDB 表,OPTIMIZE TABLE 实际上等价于 ALTER TABLE ... FORCE(MySQL 5.6+),会重建整个表并重新组织聚簇索引和二级索引,同时更新统计信息。
- 它会锁表(在可重复读隔离级别下是 ALGORITHM=COPY,全表拷贝;8.0+ 支持 INPLACE,但仍需排他 MDL 锁)
- 不适用于只读从库或高负载主库,容易触发超时或阻塞写入
- 执行后
Data_free通常归零或显著下降,但不会改变索引结构逻辑(比如不会合并单列索引为联合索引)
ALTER TABLE ... REBUILD 和 ANALYZE TABLE 的区别
ALTER TABLE t REBUILD(MySQL 8.0.23+)仅重组织物理存储,不重建索引定义;而 ANALYZE TABLE 只更新索引统计信息(用于优化器选执行计划),完全不碰数据页。
-
REBUILD是轻量级操作,不锁 DML(支持并发 INSERT/UPDATE/DELETE),适合在线整理碎片 -
ANALYZE TABLE几乎无开销,但对碎片无效——它解决的是“优化器误判”,不是“磁盘空间浪费” - 如果只是查询变慢且
EXPLAIN显示走了错误索引,先试ANALYZE TABLE;如果Data_free大且SELECT COUNT(*)响应明显变慢,再考虑REBUILD或OPTIMIZE
重建索引时最容易忽略的点
真正影响效果的不是命令本身,而是上下文约束:
- 唯一索引或主键被外键引用时,
OPTIMIZE TABLE仍能执行,但某些版本会跳过外键检查导致后续插入失败——务必提前SHOW CREATE TABLE确认外键定义 - 使用压缩表(
ROW_FORMAT=COMPRESSED)时,OPTIMIZE可能因页大小不匹配失败,报错Failed to allocate page,此时需显式指定KEY_BLOCK_SIZE - 如果表启用了加密(
ENCRYPTION='Y'),REBUILD不会改变加密状态,但OPTIMIZE在某些版本中会临时解密再重加密,延长执行时间
碎片不是越小越好——过度优化反而增加 I/O 和锁争用。观察一周内 Data_free 的增长趋势,比单次清理更重要。










