MyISAM碎片率需用Data_free/(data_length+data_free)计算,超20%建议OPTIMIZE;InnoDB不可依赖Data_free,应通过row_util_ratio(data_length/table_rows/avg_row_length)判断页内碎片,>1.5即存在明显碎片。

查 MyISAM 表碎片率:直接看 Data_free
MyISAM 不支持行级删除后的空间复用,删数据后空洞一直留着,Data_free 就是这部分“已分配但未使用”的字节数。它不等于碎片率,得自己算。
执行:
SELECT table_name, data_length, data_free, ROUND(data_free / (data_length + data_free) * 100, 2) AS frag_pct FROM information_schema.tables WHERE engine = 'MyISAM' AND table_schema = 'your_db_name';
-
data_length是实际数据占用大小,data_free是碎片空间,两者加起来才接近磁盘上该表的总占用 - 如果
data_free为 0,说明没删过或刚优化过;超过 20% 建议OPTIMIZE TABLE - 注意:
information_schema.tables的统计可能滞后,刚删完不一定立刻更新,可加ANALYZE TABLE强制刷新
查 InnoDB 表碎片率:不能只看 Data_free
InnoDB 的 Data_free 含义完全不同——它是当前最后一个 extent 里没用完的空闲页(单位是 MB),和“逻辑碎片”基本无关。真正反映碎片的是页内空闲空间利用率,得靠 INFORMATION_SCHEMA.INNODB_SYS_TABLES 和 INNODB_SYS_INDEXES 配合估算。
更实用的方法是查 avg_row_length 和 data_length 的偏离程度:
SELECT table_name, avg_row_length, data_length, table_rows, ROUND((data_length / table_rows) / avg_row_length, 2) AS row_util_ratio FROM information_schema.tables WHERE engine = 'InnoDB' AND table_schema = 'your_db_name' AND table_rows > 0;
- 如果
row_util_ratio明显大于 1(比如 > 1.5),说明平均行实际占的空间远超理论值,大概率是页内碎片高(大量 UPDATE 导致页分裂、空洞) -
table_rows是估算值,不准时会影响结果,但趋势判断仍有效 - 不要依赖
Data_free判断 InnoDB 碎片——它常为 0 或固定几 MB,跟业务写入模式无关
什么时候该优化?OPTIMIZE TABLE 对两种引擎效果差异极大
MyISAM 执行 OPTIMIZE TABLE 是重建 .MYD/.MYI 文件,彻底消除碎片,但会锁全表,期间不可读写。
面向 CRM 系统的 MySQL 8 数据库模式设计。当用户需要为客户关系管理(CRM)系统设计、评审、优化或生成数据库模式时,应使用此项技能。
InnoDB 执行 OPTIMIZE TABLE 实际等价于 ALTER TABLE ... FORCE,触发重建聚簇索引,能整理页内碎片、回收空间,但代价高:需双倍磁盘空间、锁表时间长、主从延迟风险大。
- MyISAM:碎片率 > 25% 或
Data_free > 100MB且表频繁增删,值得优化 - InnoDB:优先考虑
ALTER TABLE t ENGINE=InnoDB ROW_FORMAT=DYNAMIC;+ALGORITHM=INPLACE(5.6+),比OPTIMIZE更轻量;仅当row_util_ratio > 2.0且磁盘告警时再用OPTIMIZE - 线上大表避免在高峰执行;InnoDB 优化前确认
innodb_file_per_table=ON,否则空间无法真正释放回系统
容易被忽略的关键点:统计信息不准、监控盲区、误判场景
碎片分析最大的坑不是不会算,而是拿错指标、信错数字。
-
information_schema.tables的data_length和data_free来自内存缓存,不是实时磁盘状态;SHOW TABLE STATUS输出也一样,别当成精确值 - 小表(Data_free 波动毫无意义——InnoDB 默认 extent 大小 1MB,哪怕只多占半页也会显示 1MB
- 如果用了
innodb_page_size=4k或压缩表(ROW_FORMAT=COMPRESSED),页内碎片计算方式完全不同,上述row_util_ratio方法失效 - 真正影响性能的是随机 I/O 加剧和缓冲池命中率下降,不是碎片率本身;观察
Innodb_buffer_pool_reads和Innodb_pages_read比盯着百分比更有价值
碎片是个信号,不是病根。看到高碎片,先查是不是频繁 UPDATE 长文本字段、是不是没设 ROW_FORMAT=DYNAMIC、是不是主键设计导致页分裂严重——这些比“优化一下”重要得多。










