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

DELETE 后磁盘空间不释放,不是故障,是 InnoDB 的默认行为 —— 它只做逻辑标记,不归还页给操作系统。 想真正缩容 .ibd 文件,必须重建表结构;否则即使 SELECT COUNT(*) = 0,文件大小也纹丝不动。
为什么 OPTIMIZE TABLE 有时也不缩容
它不是“一键瘦身”命令,而是完整重建:新建 .ibd、逐行写入有效数据、原子替换。能否缩小文件,取决于当前有多少真实可合并的空闲页。
-
innodb_file_per_table = OFF时,所有表共用ibdata1,OPTIMIZE TABLE对单表无效,空间永远不释放 -
data_free值很大 ≠ 能缩容;如果刚批量插入又全删,重建后文件可能几乎不变(因为页内空洞多,但整页未被回收) - Purge 线程被阻塞(如存在长事务未提交),
SHOW ENGINE INNODB STATUS\G中History list length> 100 万时,OPTIMIZE即使跑完,实际释放量也会远低于预期 - 别在从库上直接执行 —— 它不走 binlog,主从
.ibd文件大小会不一致
线上大表不能停,怎么安全释放空间
纯 SQL 没有“在线 shrink .ibd”能力,InnoDB 引擎层不支持动态收缩数据文件。
-
pt-online-schema-change是目前最稳妥的选择:边复制边同步变更,最后原子切换,业务无感知;但要求磁盘剩余空间 ≥ 表原始大小 -
mysqldump + DROP + CREATE + INSERT可行,但耗时长、IO 压力大,且中间存在数据窗口期(dump 到 reload 之间) - 分区表可秒级释放:
ALTER TABLE t DROP PARTITION p202401会立即删除整个分区的.ibd文件;前提是建表时已定义分区,且innodb_file_per_table = ON -
ALTER TABLE t ENGINE=InnoDB和OPTIMIZE TABLE效果等价,别指望换写法绕过锁表
执行前必须检查的硬性条件
跳过这些检查,大概率导致操作失败或表不可用。
- 确认
innodb_file_per_table = ON(SHOW VARIABLES LIKE 'innodb_file_per_table'),否则所有努力白费 - 检查剩余磁盘空间 ≥ 当前
.ibd文件大小 × 1.2;重建过程需双倍临时空间 - 避免在
data_free / (data_length + index_length) > 0.3时跳过重建(碎片率超 30% 就值得干预) - 执行前先查
SELECT table_name, data_length, data_free FROM information_schema.tables WHERE table_schema='your_db' AND table_name='your_table',心里有数再动手
最容易被忽略的是 purge 阻塞和从库一致性 —— 很多人盯着 data_free 数值猛冲,却没看 History list length 是否卡住,也没意识到主从 .ibd 大小从此分裂。重建不是终点,而是清理链条中的一环。











