一聚教程网:一个值得你收藏的教程网站

热门教程

MySQL执行Delete操作后为什么磁盘空间没有立即释放?

时间:2026-08-11 07:50:49 编辑:袖梨 来源:一聚教程网

InnoDB的DELETE仅标记删除而非物理擦除,空间释放需通过OPTIMIZE TABLE或ALTER TABLE重建表实现;TRUNCATE直接重建文件,但有使用限制;Data_free高不必然需优化,应以写入延迟和磁盘压力为判断依据。

DELETE只是标记删除,不是物理擦除

InnoDB 的 DELETE 操作根本不会动磁盘文件,它只把行头的 delete_mask 位设为 1,并更新页内的空闲链表。被删的行仍躺在 .ibd 文件里,Data_lengthdu -sh table.ibd 自然纹丝不动。这不是 bug,是设计使然——为支持 MVCC、避免频繁文件截断带来的 I/O 抖动,同时让后续 INSERT 能快速复用这些“空位”。

purge线程不归还页给操作系统

后台 purge 线程负责清理已删行的 undo 日志和行级 slot,但它从不把整页还给 OS。只要没重建表,那些页就一直卡在 .ibd 里。长事务会进一步阻塞 purge:比如一个开了 20 分钟还没 COMMIT 的事务,会让所有它可能看到的旧版本数据都“不敢动”,Data_free 值越堆越高,碎片越积越多。

真正释放空间必须重建表

OPTIMIZE TABLE tALTER TABLE t ENGINE=InnoDB 效果一致,都是新建空表 → 拷贝有效数据 → 替换原 .ibd 文件。这个过程绕过标记删除逻辑,让 OS 层面回收空间。

  1. 两者都会加 MDL 锁(开始前 + 替换后各一次),慢查询或长事务卡住时,命令会挂住不动
  2. 需要额外磁盘空间 ≥ 当前表 Data_length 的 1.5 倍,否则临时文件写满直接报 ERROR 1034
  3. RDS 等托管服务可能禁用 OPTIMIZE TABLE 或转到只读副本执行,得查控制台文档确认

TRUNCATE和WHERE删除要分场景用

TRUNCATE TABLE t 是删文件再建新 .ibd,立刻释放空间,但它不走事务、不触发触发器、外键子表上会报 ERROR 1701;如果只删部分数据,mysqldump --where="create_time t_old.sql 导出有效数据再重建导入,比盲目 OPTIMIZE 更安全。

真正容易被忽略的是:Data_free 高 ≠ 必须优化——它本就是为写入预留的缓冲空间;重建表的关键,从来不是“删了就得缩”,而是判断当前碎片是否已影响写入延迟、磁盘是否真快撑不住了。

热门栏目