MyISAM表执行OPTIMIZE TABLE会真实缩小.MYD/.MYI文件体积,而InnoDB表则等价于ALTER TABLE ... ALGORITHM=COPY,仅当innodb_file_per_table=1且DATA_FREE显著时才缩.ibd;ALGORITHM=INPLACE不缩磁盘但可优化页布局。

MyISAM表执行OPTIMIZE TABLE会真正缩文件
MyISAM引擎下,OPTIMIZE TABLE是原生支持的碎片回收方式,它会直接重建.MYD和.MYI文件,把数据和索引重新排序、合并空闲块,并**真实减小磁盘文件体积**。
常见错误现象:执行后DATA_FREE变成0,但ls -lh tbl.MYD没变小——大概率是表刚创建或没经历过DELETE,根本没产生碎片。
使用场景有限,仅适用于MyISAM表;InnoDB表走这条路只是“看起来一样”,实际行为完全不同。
- 无需额外参数,
OPTIMIZE TABLE myisam_tbl即可 - 过程会锁表(读写都阻塞),大表慎用
- 不依赖
innodb_file_per_table等配置,因为MyISAM本来就是每表独立文件
InnoDB表执行OPTIMIZE TABLE本质是ALTER TABLE ... ALGORITHM=COPY
InnoDB在MySQL 5.6+中,OPTIMIZE TABLE只是ALTER TABLE tbl ENGINE=InnoDB ALGORITHM=COPY的别名,不是轻量整理,而是“删旧建新+全量拷贝”。它能释放.ibd文件空间,但必须同时满足三个硬条件:
-
SELECT @@innodb_file_per_table返回1(默认开启,但老实例可能关了) -
SHOW TABLE STATUS LIKE 'tbl'中DATA_FREE值显著(比如 > 100MB),说明有真实内部碎片 - 执行前无长事务、无活跃备份(如
mysqldump --single-transaction正在跑)
不满足任一条件,.ibd大小不会变,df -h自然也看不到变化。别怪命令没用,先查DATA_FREE和innodb_file_per_table。
想不锁表又整理InnoDB?用ALGORITHM=INPLACE但别指望缩磁盘
如果目标只是让页更紧凑、DATA_FREE归零、提升查询局部性,而不是省磁盘,ALTER TABLE tbl ENGINE=InnoDB ALGORITHM=INPLACE LOCK=NONE更安全:
- 只持短时间元数据锁,DML基本不受影响
- 不生成临时文件,磁盘压力小
- 但
.ibd文件大小不变——它不释放未用页给文件系统,只是重排已有页
所以别在监控告警说“磁盘快满了”时跑这个,它救不了df -h。
执行前必须人工确认的三件事
线上误跑OPTIMIZE TABLE可能拖垮服务,动手前盯死这三点:
- 磁盘剩余空间 ≥
DATA_LENGTH + INDEX_LENGTH(重建需双倍空间,df -h /var/lib/mysql看准) -
SHOW PROCESSLIST里没有State: Waiting for table flush或运行超30分钟的事务 - 主库避开高峰,从库执行前先
STOP SLAVE,否则relay log延迟可能导致主从.ibd大小不一致
最常被忽略的是innodb_file_per_table=OFF状态下的徒劳操作——此时所有InnoDB表共享ibdata1,OPTIMIZE TABLE连.ibd都不会碰,更别说缩空间了。


















