InnoDB的DELETE仅逻辑标记删除,不释放物理磁盘空间;必须通过OPTIMIZE TABLE或ALTER TABLE ENGINE=InnoDB重建表才能真正释放.ibd文件空间。

DELETE 不会缩小 .ibd 文件大小,这是 InnoDB 的正常行为,不是 bug,也不是配置错误。
DELETE 本质是标记删除,不是物理擦除
InnoDB 的 DELETE 操作只在记录头(record header)打上 deleted_flag=1 标记,并把该记录所在的位置加入“空闲链表”,供后续插入复用。磁盘上的数据页(page)本身不被回收,文件系统层面的 .ibd 文件尺寸自然不变。
- 即使删光整张表,
Data_length和Data_free在SHOW TABLE STATUS中也几乎不变 - 被标记删除的记录仍占用空间,直到有新记录按 B+ 树顺序恰好能填入其位置(例如主键值落在相邻记录区间内)
- 如果新插入的主键值“跳得太远”,旧记录位置就长期闲置——这就是“空洞”
innodb_file_per_table=OFF 时空间根本无法释放
这个参数决定数据是否存进独立 .ibd 文件。若为 OFF,所有表数据都挤在共享表空间 ibdata1 里,哪怕执行 DROP TABLE,空间也不会还给操作系统——因为 ibdata1 只增不减。
-
SHOW VARIABLES LIKE 'innodb_file_per_table';必须返回ON,才可能通过重建表真正收缩文件 - MySQL 5.6.6+ 默认为
ON,但老实例或手动调优过可能仍是OFF - 改回
ON只对新建表生效;已有表需ALTER TABLE ... ENGINE=InnoDB才能迁出共享空间
真正释放空间必须重建表结构
只有重建才能让 InnoDB 把有效数据重新紧凑写入新页,丢弃所有标记删除的记录和碎片页。推荐优先用 OPTIMIZE TABLE 或 ALTER TABLE ... ENGINE=InnoDB,二者在 innodb_file_per_table=ON 下效果一致。
-
OPTIMIZE TABLE t;是最直接方式,MySQL 会自动判断并执行 online DDL(5.6+) -
ALTER TABLE t ENGINE=InnoDB;更明确,适合需要指定 ALGORITHM 的场景,如:ALGORITHM=INPLACE, LOCK=NONE - 避免用
TRUNCATE TABLE来“清空再重插”:它虽快且释放空间,但会重置AUTO_INCREMENT,且无法带条件,也不适用于部分删除后想留痕的场景 - 大表重建期间会加元数据锁(MDL),建议在低峰期操作;可配合
pt-online-schema-change实现无锁重建
空洞不是异常状态,而是 InnoDB 为兼顾写入性能和 MVCC 做出的设计权衡。真正要缩文件,绕不开重建这一步——别指望 DELETE 或 ANALYZE TABLE 能改变 .ibd 大小。











