文档首页> 技术教程> 数据库文件膨胀:碎片整理与表优化

数据库文件膨胀:碎片整理与表优化

发布时间:2026-01-09 21:49        更新时间:2026-01-10 05:06
表里的数据删掉一大半,磁盘占用却纹丝不动,这不是错觉。弄明白删除为什么不像想象中那样释放空间,才能正确地把空间收回来。 删除为什么不释放空间 InnoDB 删除一行只是在记录上打删除标记,这块空间标记为可复用,并不会立刻还给操作系统;表文件原地保留,等后来的插入来填。所以删掉 80% 的数据,物理文件可能一点没小,而且复用优先填中间的空洞,文件尾部的空间照样闲着。 怎么把空间收回来 核心思路是重建表:按当前存活数据生成一份紧凑的新表文件,再原子替换。MySQL 5.6 起 online 重建支持并发读写: OPTIMIZE TABLE bigtable; 执行期间业务可以继续读写(收尾阶段有短暂锁),完成后空间归还操作系统。前提是 innodb_file_per_table=ON,也就是每张表一个独立文件;共享表空间模式下 OPTIMIZE 只会把共享文件撑得更大,收不回来。 另一个选择是手工版"建新表换名字":create table t_new like t; 分批把存活数据搬进去,低峰一次性 rename 切换。做法笨一点,但进度可控、随时能停,适合不敢直接跑 OPTIMIZE 的场景。搬迁脚本按主键分段循环,每批一万行,中间稍作停顿,把影响摊平。 执行时机与风险 重建期间磁盘上同时存在新旧两份数据,动手前确认磁盘余量至少还有一倍表体积。主从架构下,大表重建会以大事务形式同步到从库,容易把延迟顶起来;先在从库试算耗时,挑业务低峰,别和备份窗口、大报表任务撞车。 一点提醒 频繁大批量删除的业务,与其反复整理,不如把删除改成按时间分表或分区,旧数据整个 drop 分区,空间回收天然是原子操作。碎片整理是补救手段,分区设计才是根治办法。另外分区表要配合查询习惯:条件里带上分区键才能裁剪扫描范围,改造前先确认业务 SQL 的形状。