DELETE不释放磁盘空间是InnoDB设计使然,仅标记删除而不回收页;需用ALTER TABLE/OPTIMIZE TABLE或pt-online-schema-change重建表才能真正缩文件,前提是innodb_file_per_table=ON且磁盘空间充足。

DELETE 后磁盘空间不释放,不是你删错了,也不是 MySQL 抽风——这是 InnoDB 的默认行为。想真正缩文件,必须重建表。
为什么 DELETE 不缩 .ibd 文件大小?
InnoDB 的 DELETE 只是把行头的 delete_mask 位设为 1,物理页仍保留在 .ibd 文件里,等待后续 INSERT 复用。它不还页给操作系统,也不动文件尺寸。
- 现象包括:
SHOW TABLE STATUS中Data_length几乎不变,Data_free反而升高 -
du -sh table.ibd显示大小纹丝不动,哪怕SELECT COUNT(*) = 0 - 本质是设计取舍:用空间换 MVCC 正确性、并发写入稳定性、页复用效率
真正释放空间的三种可行方式(按推荐顺序)
核心逻辑只有一条:把有效数据重写进新页,旧页丢弃,文件系统才能回收。
-
ALTER TABLE t ENGINE=InnoDB:语义清晰,RDS 多数支持 Online DDL;MySQL 5.7+ 默认走ALGORITHM=INPLACE,但需确认是否加了LOCK=NONE -
OPTIMIZE TABLE t:等价于ALTER TABLE t FORCE,5.7+ 自动带ANALYZE;注意它会在开始前和替换后各加一次 MDL 锁,可能卡慢查询 -
pt-online-schema-change --alter "ENGINE=InnoDB" --execute:超大表或不能锁表时用,不阻塞 DML,但依赖 Percona Toolkit 和额外磁盘空间
执行前必须检查的三件事
盲目跑重建命令,轻则失败,重则卡死实例。
- 磁盘剩余空间 ≥ 当前
Data_length× 1.2 —— 临时表 + redo + undo 都要落盘 - 查长事务:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(TIMEDIFF(NOW(), trx_started)) > 600;若有,purge 卡住,重建也清不干净 - 看碎片程度:
SHOW TABLE STATUS LIKE 't'\G,若Data_free占Data_length超 10%,才值得优化;几百 KB 就别折腾了
容易忽略的关键前提
所有重建操作都依赖 innodb_file_per_table = ON。如果关着,表数据全堆在 ibdata1 里,ALTER 或 OPTIMIZE 根本无效——你只是在原地打转。
另外,TRUNCATE TABLE 和 DROP TABLE 能立刻释放空间,但它们不可逆、会重置自增、需要更高权限,且不适用于“删部分数据”的场景。

















