InnoDB和MyISAM的DELETE后空间释放行为不同:InnoDB仅标记删除不立即释放,MyISAM直接回收;碎片率应通过INFORMATION_SCHEMA.TABLES计算;OPTIMIZE TABLE与ALTER TABLE ... ENGINE=InnoDB对InnoDB效果近似但锁表现不同;MyISAM需停服用myisamchk修复;碎片整理应按需而非定期执行。

DELETE后空间不释放?InnoDB和MyISAM行为完全不同
执行 DELETE FROM t WHERE id 后,磁盘空间没变小——这不是MySQL卡了,是引擎机制决定的。InnoDB 不会立刻归还空间给操作系统,只是把行标记为“可复用”,而 MyISAM 在删整表数据时(<code>DELETE FROM t)会直接收缩.MYD文件。
- InnoDB:靠后台
Purge线程异步清理,空洞留在表空间内,Data_free字段会变大 - MyISAM:整表
DELETE会立即释放磁盘,但带WHERE条件的删除仍留空洞 - 两者都支持
OPTIMIZE TABLE强制重建,但 InnoDB 下它本质是ALTER TABLE ... ENGINE=InnoDB的语法糖
怎么确认表到底有没有碎片?别只看文件大小
直接 ls -lh table_name.ibd 容易误判——因为 innodb_file_per_table=ON 时,.ibd 文件可能包含大量未分配页;真正该看的是 MySQL 内部统计值。
- 查
SHOW TABLE STATUS LIKE 't'\G,重点盯Data_free(单位字节),>100MB 就值得处理 - 更准的方式:从
INFORMATION_SCHEMA.TABLES算碎片率:SELECT table_name, ROUND(data_free / (data_length + index_length), 4) AS frag_ratio FROM INFORMATION_SCHEMA.TABLES WHERE engine='InnoDB' AND data_free > 100*1024*1024; - 注意:
ANALYZE TABLE不整理碎片,只更新索引统计信息,别把它和OPTIMIZE搞混
OPTIMIZE TABLE 和 ALTER TABLE ... ENGINE=InnoDB 有什么区别?
对 InnoDB 表来说,二者效果几乎一样:都是重建聚簇索引+重新分配页+合并空洞。但底层动作略有不同,影响操作时长和锁表现。
-
OPTIMIZE TABLE t:MySQL 自动判断引擎类型,内部转成ALTER TABLE t FORCE或等效操作,会触发元数据锁(MDL)写锁,期间不能 DDL/DML -
ALTER TABLE t ENGINE=InnoDB:显式重建,语义更清晰;若表已用 InnoDB,MySQL 5.6+ 会跳过实际拷贝(fast index creation),但仍有锁表时间 - 都不支持在线(online DDL)的旧版本(如 MySQL 5.5),建议升级到 5.7+ 并确认
innodb_fast_alter_table=ON
MyISAM 要额外注意 myisamchk,但别在运行时硬来
MyISAM 的 OPTIMIZE TABLE 虽然也能用,但它依赖表级锁且无法修复损坏索引;真正彻底整理得用 myisamchk,但这要求 MySQL 完全停止。
- 停服务后执行:
myisamchk -r -q /var/lib/mysql/db/t.MYI,-r是修复,-q是快速模式(跳过排序) - 切勿在 mysqld 运行时直接跑
myisamchk,否则可能破坏表结构,出现Client does not support authentication protocol类错误 - MyISAM 已被官方标记为“deprecated”,新项目别再用;老系统若必须维护,建议优先迁移到 InnoDB
碎片整理不是“越勤越好”——一次 OPTIMIZE 可能锁表几十秒甚至分钟,尤其大表。真正该关注的是 Data_free 是否持续增长、查询是否明显变慢、以及磁盘空间是否真的吃紧。盲目定期执行,反而可能引入稳定性风险。


















