innodb的delete仅逻辑标记删除,不释放物理空间;必须通过optimize table或alter table engine=innodb重建表,并满足innodb_file_per_table=on、磁盘冗余≥1.2倍data_length、无长事务阻塞purge三个前提才能真正释放空间。

DELETE 不释放物理磁盘空间,是 InnoDB 引擎的确定性行为,不是配置错误、没生效或磁盘异常——它压根就不把页还给操作系统。
DELETE 只是标记删除,不碰 .ibd 文件大小
InnoDB 的 DELETE 操作本质是逻辑删除:仅将行头的 delete_mask 位设为 1,并更新页内空闲链表。整块数据页仍保留在 .ibd 文件中,供后续 INSERT 复用。
这意味着:
-
du -sh table.ibd输出完全不变 -
SHOW TABLE STATUS LIKE 't'\G中的Data_length几乎不降,哪怕SELECT COUNT(*) = 0 -
Data_free值反而可能变大——它代表“可复用但未归还 OS”的页数,不是已释放空间
真正释放空间必须重建表,且只对独立表空间有效
只有物理重建才能让操作系统回收空间,核心手段就两个:OPTIMIZE TABLE t 和 ALTER TABLE t ENGINE=InnoDB。它们在 InnoDB 表上效果一致:新建空表 → 拷贝有效行 → 替换原 .ibd → 删除旧文件。
但前提是:
-
innodb_file_per_table = ON(必须开启,否则数据锁在共享表空间ibdata1里,重建也白搭) - 磁盘剩余空间 ≥ 当前表的
Data_length× 1.2(临时表 + 新索引要写两份) - 无长事务阻塞 purge:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW() - trx_started) > 600结果应为空
OPTIMIZE TABLE 执行失败的典型报错和原因
跳过前置检查,OPTIMIZE TABLE 极易卡住或中断,常见现象包括:
-
ERROR 1034 (HY000): Incorrect key file for table:磁盘写满,临时表无法落盘 - 长时间卡在
Waiting for table metadata lock:有慢查询、SELECT ... FOR UPDATE或 DDL 正在执行 - 主从
.ibd文件大小不一致:该操作不写 binlog(ROW 格式下),从库不会同步 - 执行完
.ibd大小几乎没变:表本身就很紧凑(比如刚 INSERT 就 DELETE),没多少空洞可合并
分区表 DROP PARTITION 是唯一秒级释放方案
如果你的表是按时间分区(如 PARTITION BY RANGE (created_at)),直接 ALTER TABLE t DROP PARTITION p202401 就能立刻从文件系统删除整个分区的 .ibd 文件,空间秒还 OS。
但硬性限制很明确:
- 建表时就必须定义分区,事后加分区需
REORGANIZE,仍触发全量拷贝 -
innodb_file_per_table = ON必须开启,否则分区数据也混在ibdata1中 - 仅适用于归档类场景(日志、流水),不适用于频繁更新的热表
最常被忽略的一点:即使你删光了整张表,只要没重建,.ibd 就永远维持原尺寸;而重建又依赖磁盘余量、purge 进度和引擎配置三者同时满足——缺一不可,少查一项就大概率失败。











