DELETE后磁盘空间不释放是InnoDB正常设计,因仅逻辑标记删除行而不物理回收,必须通过OPTIMIZE TABLE或ALTER TABLE ENGINE=InnoDB重建表才能真正缩容.ibd文件。

DELETE 后磁盘空间不释放,是 InnoDB 的设计行为,不是故障,也不是配置错误。想让 .ibd 文件真正变小,必须重建表——OPTIMIZE TABLE 是最直接的手段,但它有硬约束,不能无脑执行。
为什么 DELETE 不缩 .ibd 文件
InnoDB 删除行只是打上 deleted 标记,页(Page)仍保留在文件里,供后续 INSERT 复用。所以 du -sh table.ibd、DATA_LENGTH、SHOW TABLE STATUS 都不会变小。
- 即使
SELECT COUNT(*) = 0,只要没重建,文件尺寸纹丝不动 -
innodb_file_per_table = OFF时,所有表共用ibdata1,删再多也永远不缩 —— 这个参数必须为ON才有释放可能 - Purge 线程只清理 undo 日志和行级 slot,**不把页还给操作系统**
- TRUNCATE 或 DROP 才会立即释放文件级空间;DELETE 永远不等于清空磁盘
OPTIMIZE TABLE 实际做了什么
它不是“整理碎片”的魔法命令,而是触发一次完整重建:CREATE TABLE new AS SELECT * FROM old + DROP old + RENAME new → old。所有数据重写进新页,旧页丢弃,OS 层面才真正归还空间。
- 执行前务必确认
innodb_file_per_table = ON,否则重建后仍写入ibdata1,白忙一场 - MySQL 8.0 默认走
ALGORITHM=INPLACE,但OPTIMIZE TABLE仍需短暂加 DDL 锁,大表可能卡住元数据锁(metadata lock) -
Data_free值很大 ≠ 能缩容;如果表本身很稀疏(比如刚批量插入又全删),重建后文件大小可能几乎不变 - 别在从库上直接跑 —— 它不走 binlog,主从
.ibd文件大小会不一致
线上大表不能停,还能怎么释放空间
纯 SQL 没有“在线 shrink .ibd”的能力。InnoDB 不支持动态收缩数据文件,这是引擎层硬限制。
-
pt-online-schema-change是目前最稳妥的方案:边复制边同步,最后原子切换,业务无感知,但要求磁盘剩余空间 ≥ 表原始大小 -
mysqldump + DROP + CREATE + INSERT可行,但耗时长、IO 压力大,且中间存在数据窗口期 -
ALTER TABLE t ENGINE=InnoDB和OPTIMIZE TABLE效果等价,别以为换写法就能绕过锁表 - 压缩表(
ROW_FORMAT=COMPRESSED)只影响新写入数据密度,对已有.ibd文件大小 **零影响**
最容易被忽略的是:重建操作本身会短暂占用双倍磁盘空间,且 purge 被阻塞时(比如有长事务未提交),OPTIMIZE TABLE 即使跑完,实际释放量也可能远低于预期——得先看 SHOW ENGINE INNODB STATUS\G 里的历史列表长度。











