delete后磁盘空间不释放是innodb正常行为,因仅标记删除而不物理回收;需执行optimize table(等价alter table engine=innodb)重建表才能真正释放空间,但须满足innodb_file_per_table=on、无长事务、磁盘空间充足等条件。

DELETE 后磁盘空间不释放是 InnoDB 的正常行为,不是 bug,也不是配置错误。它根本不会删物理文件,只打删除标记,等新数据来复用——所以 Data_length 不变、df -h 看不到空间回来。
为什么 OPTIMIZE TABLE 能释放空间
它本质是重建表:把有效数据拷到新页,丢掉所有带删除标记的行和空洞,再替换原表文件。InnoDB 引擎下,这等价于执行 ALTER TABLE t ENGINE=InnoDB。
- 仅对已执行过大量
DELETE或UPDATE的表有效;没删过数据就跑OPTIMIZE TABLE,Data_free可能反而变大(因临时表开销) - 必须确保磁盘剩余空间 ≥ 当前表的
Data_length;否则会卡在“创建临时表”阶段并报错ERROR 1034 (HY000): Incorrect key file for table - MySQL 5.7+ 支持 Online DDL,但仍有短暂 metadata lock —— 表上正跑着
SELECT ... FOR UPDATE或长事务时,OPTIMIZE会卡住,直到锁释放
执行 OPTIMIZE TABLE 前必须检查的三件事
跳过任意一项都可能引发锁表、OOM 或磁盘写满。
- 查当前磁盘水位:
df -h /var/lib/mysql,确认剩余空间 >SHOW TABLE STATUS LIKE 't'\G中的Data_length - 查是否有长事务阻塞:
SELECT * FROM information_schema.INNODB_TRX WHERE TIME_TO_SEC(NOW() - trx_started) > 60; - 确认表引擎是 InnoDB:
SHOW CREATE TABLE t\G,输出里必须含ENGINE=InnoDB;MyISAM 表虽也支持OPTIMIZE,但机制不同,此处不适用
替代方案:什么情况下不该用 OPTIMIZE TABLE
当表太大(比如 >100GB)、或磁盘已超 85% 使用率时,OPTIMIZE 风险极高。这时更稳妥的是:
- 用
TRUNCATE TABLE t替代DELETE FROM t—— 它直接删文件再重建,立刻释放空间,但无法加 WHERE 条件 - 对历史归档表,停机导出有效数据:
mysqldump -u root -p --where="create_time > '2025-01-01'" db t > t_recent.sql,再重建表导入 - 长期看,开启
innodb_file_per_table=ON(需重启),让每张表独占 .ibd 文件,后续DROP TABLE才能真正删磁盘文件
真正容易被忽略的点是:Data_free 字段值高 ≠ 一定要优化;它只是“当前可复用的空页数”,只要业务写入模式稳定、没有明显慢查询,这些空间本就是为性能预留的缓冲。盲目优化大表,反而可能把 IO 峰值引向非预期时段。











