OPTIMIZE TABLE在InnoDB上本质是重建表(ALTER TABLE ... ENGINE=InnoDB),创建新.ibd文件、按聚簇顺序重写数据和索引,并回收已DELETE但未物理释放的空闲空间;需确保磁盘剩余空间≥原.ibd大小,且仅当DATA_FREE>0时才有效。

OPTIMIZE TABLE在InnoDB上到底做了什么
在MySQL 5.7中,对InnoDB表执行OPTIMIZE TABLE,**本质上等价于执行ALTER TABLE tbl_name ENGINE=InnoDB**——即重建整张表。它会创建新的.ibd文件,把数据和索引按聚簇顺序重新写入,同时丢弃被标记为“可复用”但长期未被填充的页内空闲空间。这不是简单的碎片整理,而是物理文件级的重写。
你看到的提示Table does not support optimize, doing recreate + analyze instead不是报错,是MySQL 5.7+的正常日志输出,说明它已自动降级为重建流程。
必须先DELETE,否则OPTIMIZE无效
OPTIMIZE TABLE不会凭空压缩空间;它只回收那些已被DELETE逻辑删除、但尚未被物理释放的块。如果表里没删过数据,或者只删了极少量(比如几行),执行后.ibd文件大小几乎不变。
- 确认是否真有可回收空间:查
information_schema.TABLES中DATA_FREE字段,值大于0才值得操作 - 删除动作要显式完成:不能只靠应用层软删(如加
is_deleted=1),必须执行DELETE FROM table WHERE ... - 大表删数据建议分批提交,避免长事务撑爆undo log
执行时磁盘空间会临时翻倍
因为MySQL需同时持有原.ibd文件和新重建的临时文件,**实例剩余磁盘空间必须 ≥ 当前表.ibd文件大小**。否则会失败并卡在“copying to tmp table”阶段。
- 可通过
SELECT file_size/1024/1024 AS mb FROM information_schema.INNODB_SYS_TABLESPACES WHERE name = 'db/table';估算所需空间 - RDS用户务必提前扩容磁盘;自建库需确保
datadir所在分区有足够余量 - 执行期间监控
df -h,避免因磁盘满导致MySQL进程OOM或崩溃
别在高峰期跑,锁和IO压力比你想的更狠
MySQL 5.7虽支持Online DDL,但OPTIMIZE TABLE仍会触发全表扫描+大量随机I/O,在SSD上可能不明显,但在机械盘或高负载实例上极易引发雪崩。
- 主从架构下,该操作会生成巨量binlog,从库可能瞬间延迟飙升
- 即使没锁表,Buffer Pool会被大量新页填满,挤出热点数据,导致后续查询缓存命中率骤降
- 建议用
pt-osc替代(对大表),或改用ALTER TABLE ... ALGORITHM=INPLACE配合LOCK=NONE的组合(需满足条件)
最常被忽略的一点:OPTIMIZE TABLE完成后,DATA_FREE归零,但information_schema.TABLES里的DATA_LENGTH和INDEX_LENGTH可能滞后更新——要等下次ANALYZE TABLE或MySQL重启才会准确反映磁盘占用。别只看这个值判断是否成功。


















