optimize table 能清理 innodb 表空间碎片是因为它实际执行 alter table ... force,重建整张表:申请新段、逐行拷贝数据、释放旧页,消除页内碎片和页间空洞。

OPTIMIZE TABLE 为什么能清理 InnoDB 表空间碎片
因为 OPTIMIZE TABLE 对 InnoDB 表实际执行的是 ALTER TABLE ... FORCE,会重建整张表:申请新段、逐行拷贝数据、释放旧页,从而消除页内碎片和页间空洞。这不是“整理”,而是“换一套房子住”。
注意:它不会回收被 DROP TABLE 或 TRUNCATE TABLE 释放但未归还给操作系统的磁盘空间(那是 innodb_file_per_table=ON 下的.ibd文件大小问题)。
- 仅对
innodb_file_per_table=ON的表有效(默认开启,但老实例可能关着) - 执行期间表会被加
SX锁,写操作阻塞,读操作一般不受影响(取决于 MySQL 版本) - 会产生大量 redo log 和临时 sort buffer,高峰期慎用
执行 OPTIMIZE TABLE 前必须检查的三件事
很多人直接跑命令,结果卡住或失败——多数问题出在准备阶段。
- 确认表引擎是
InnoDB:SHOW CREATE TABLE `t_name`,看到ENGINE=InnoDB才继续 - 检查磁盘剩余空间是否 ≥ 当前表
.ibd文件大小的 1.5 倍(重建过程需要临时空间) - 查
information_schema.INNODB_TABLESPACES或ls -lh /var/lib/mysql/db_name/t_name.ibd,确认该表确实是独立表空间(FILE_SIZE > 0且不是系统表)
OPTIMIZE TABLE 在不同场景下的替代方案
不是所有“碎片”都需要 OPTIMIZE TABLE;它重、慢、锁表,有些情况纯属浪费资源。
- 表刚
DELETE大量行,但后续还有持续写入 → 改用ALTER TABLE t_name ENGINE=InnoDB(效果相同,语义更明确) - 想回收磁盘空间但表很大(>50GB)、业务不能停 → 走
pt-online-schema-change --alter "ENGINE=InnoDB" --execute - 只是索引统计信息过期 → 直接
ANALYZE TABLE t_name,快且无锁 - 误删了数据又没备份 →
OPTIMIZE TABLE会彻底丢弃已标记删除但未 purge 的记录,别用
常见报错和对应处理方式
ERROR 1036 (HY000): Table 't_name' is read only:通常是 read_only=1 或从库开启了 super_read_only,需临时关闭(主库上也要确认用户权限含 ALTER 和 INSERT)
ERROR 1795 (HY000): ALTER operation not supported for this table type:说明这张表是 MyISAM 或分区表的某个子分区不支持,先 SHOW CREATE TABLE 确认类型
-
ERROR 2013 (HY000): Lost connection to MySQL server during query:大概率是超时或内存溢出,调大innodb_online_alter_log_max_size和wait_timeout - 执行后
.ibd文件没变小?可能是innodb_file_per_table=OFF,或表空间被其他表共享(如系统表),此时优化无效
碎片这事,本质是空间复用效率问题。真正难的不是命令怎么敲,而是判断“此刻要不要动”——看监控里 Innodb_page_size 和 Innodb_data_written 的比值,比平均值低 20% 以上再动手,不然就是拿业务稳定性换一个数字好看。











