OPTIMIZE TABLE 不一定释放磁盘空间:InnoDB 仅标记空间可复用,.ibd 文件通常不缩;MyISAM 才真正缩小文件。适用场景包括大量删改后 Data_free >100MB(InnoDB)、DELETE 超20%(MyISAM)等。

OPTIMIZE TABLE 会真正释放磁盘空间吗
不一定。对 InnoDB 表,OPTIMIZE TABLE 实际执行的是 ALTER TABLE ... ENGINE=InnoDB,它会重建表、整理数据页、更新统计信息,并标记原聚簇索引中未使用的空间为“可复用”。但这些空间通常不会立即返还给操作系统——.ibd 文件大小往往不变,除非启用了 innodb_file_per_table=ON 且满足碎片回收条件(如大量 DELETE 后的空页被彻底清理)。而 MyISAM 表则会直接缩小 .MYD 和 .MYI 文件。
哪些场景下执行 OPTIMIZE TABLE 才有意义
别一看到“碎片”就跑命令。真正值得优化的场景很具体:
-
InnoDB表:开启innodb_file_per_table=ON,且近期执行过大量DELETE或UPDATE(尤其是涉及大字段如TEXT/BLOB),SHOW TABLE STATUS中的Data_free值持续 > 100MB; -
MyISAM表:含VARCHAR/TEXT等变长字段,且DELETE比例超过 20%,myisamchk -s显示明显碎片; - 全文索引表:对
InnoDB的FULLTEXT索引做了大量增删改,需先设SET innodb_optimize_fulltext_only=1再执行; - 统计信息严重滞后:
EXPLAIN显示行数估算偏差极大(比如实际 10 万行,估算成 100 行),且ANALYZE TABLE无效时,可尝试OPTIMIZE强制刷新。
执行时必须避开的坑
OPTIMIZE TABLE 不是后台小任务,它在多数引擎上会锁表:
-
InnoDB:5.6+ 版本使用 online DDL(仅短暂加 MDL 锁),但重建过程仍占用大量 I/O 和 CPU,高并发写入下可能触发超时或主从延迟; -
MyISAM:全程独占写锁,期间所有INSERT/UPDATE/DELETE都阻塞,读操作虽可继续但可能被卡住; - binlog 风险:默认写入 binlog,若主库压力大或网络慢,从库延迟可能飙升;加
NO_WRITE_TO_BINLOG可跳过,但会破坏主从一致性,慎用; - 权限要求:必须同时拥有
SELECT和INSERT权限,仅DROP或ALTER权限不够; - 误判空间:别只看
Data_free,还要对比Data_length和实际数据量——如果Data_length本身很小,Data_free大只是相对值,不意味真有几十 GB 碎片。
替代方案比 OPTIMIZE 更轻量
日常维护中,多数情况不需要 OPTIMIZE TABLE:
- 优先用
ANALYZE TABLE:只更新统计信息,毫秒级完成,无锁,解决 80% 的执行计划误判问题; - 定期归档删除:对日志类表,用
DELETE ... LIMIT 10000分批删 +OPTIMIZE,比一次性删完再优化更稳; - 建表时预防:
InnoDB表务必开innodb_file_per_table=ON;变长字段多的表,预估容量时留 15%~20% 空间余量; - 监控代替盲优化:用
information_schema.INNODB_SYS_TABLESPACES查FILE_SIZE与ALLOCATED_SIZE差值,比Data_free更准。
真正要动手前,先跑一遍 SHOW TABLE STATUS LIKE 'your_table',盯着 Data_free、Rows、Engine 三列看——数值没到量级,就别动它。


















