Data_free 不是索引碎片,而是表空间中未使用的字节数,无法反映索引逻辑碎片程度;真正评估需结合 INFORMATION_SCHEMA.INNODB_SYS_INDEXES 等视图分析页利用率与数据量比值。

SHOW TABLE STATUS 里 Data_free 是索引碎片吗?
不是。Data_free 表示表空间中未被使用的字节数,它和索引碎片没有直接对应关系。InnoDB 表的 Data_free 主要反映的是最近一次 OPTIMIZE TABLE 或 ALTER TABLE 操作后留下的空闲页(来自 B+ 树页分裂或删除后的空洞),但它不区分数据页还是索引页,也不反映实际的逻辑碎片程度。
常见错误现象:Data_free 值很大(比如几百 MB),就以为“索引很碎”,急着跑 OPTIMIZE TABLE——结果发现查询没变快,还锁表、占磁盘、触发长事务阻塞。
- InnoDB 的聚簇索引和二级索引都存储在同一个表空间(
ibdata1或独立.ibd文件)里,Data_free是整个文件级别的统计,无法拆解到单个索引 - MyISAM 表的
Data_free才更接近“数据文件空洞”,但依然不等于索引碎片(它的索引是单独的.MYI文件) - 真正影响查询性能的,是索引页的填充率、B+ 树深度、以及随机 I/O 比例,这些
SHOW TABLE STATUS根本不提供
怎么真正评估 InnoDB 索引碎片?
看 INFORMATION_SCHEMA.INNODB_SYS_INDEXES 和 INFORMATION_SCHEMA.INNODB_SYS_TABLES,结合 avg_data_length / avg_row_length 和页利用率估算。
使用场景:需要判断是否值得对某张大表做 OPTIMIZE TABLE 或重建索引(如 ALTER TABLE ... FORCE)时,必须交叉验证。
- 查索引页数与实际数据量比值:
SELECT index_name, n_fields, page_count, n_leaf_pages FROM INFORMATION_SCHEMA.INNODB_SYS_INDEXES WHERE table_name = 'your_table' - 对比
DATA_LENGTH(数据+索引总大小)和(TABLE_ROWS × AVG_ROW_LENGTH):如果前者远大于后者,说明存在较多空洞(但不一定是索引导致) - 更准的方式是用
mysqlcheck --analyze或 Percona Toolkit 的pt-table-checksum+pt-index-usage组合分析访问模式和冗余度
OPTIMIZE TABLE 真的能“整理索引碎片”吗?
对 InnoDB 来说,OPTIMIZE TABLE 实质是重建表(ALTER TABLE ... ENGINE=InnoDB),会重新组织聚簇索引和所有二级索引的物理存储,清空 Data_free,但代价很高。
性能 / 兼容性影响明显:5.6+ 默认用 online DDL,但仍需排他元数据锁(MDL);8.0 支持部分 online 场景,但 OPTIMIZE 仍可能阻塞写入。
- 只在满足以下条件时才考虑:
DATA_FREE > DATA_LENGTH × 0.3且该表是高频读写、有明显慢查询、且执行窗口可控 - 不要对
innodb_file_per_table = OFF的实例轻易操作,Data_free可能属于共享表空间,OPTIMIZE不起作用 - 替代方案更轻量:对单个索引用
ALTER TABLE t DROP INDEX idx_name, ADD INDEX idx_name (...)(MySQL 5.7+ 支持 online add/drop index)
为什么 SHOW INDEX FROM 不显示碎片信息?
SHOW INDEX FROM 只返回索引定义元数据(列顺序、唯一性、类型等),不包含任何物理存储状态。它连索引大小都不报,更别说碎片了。
容易踩的坑:有人看到 Cardinality 值不准,就以为是“索引坏了”或“碎片高”,其实那是统计信息过期,运行 ANALYZE TABLE 就行,跟碎片无关。
-
Cardinality是采样估算值,受innodb_stats_auto_recalc和innodb_stats_persistent控制,和磁盘上页是否紧凑完全无关 - 想看索引实际占用空间,得查
INFORMATION_SCHEMA.INNODB_SYS_INDEXES的page_count字段,再结合INNODB_PAGE_SIZE(默认 16KB)换算 - 没有命令能一键输出“索引碎片率%”,这是 DBA 需要自己建模估算的点,别指望 MySQL 自带视图全包圆
碎片不是开关式问题,它是数据变更模式、索引设计、缓冲池命中率、甚至硬件 I/O 能力共同作用的结果。盯着 Data_free 做决策,就像靠体重秤诊断高血压。


















