alter table启用页压缩必须搭配重建才能释放空间,仅设compression参数不回收磁盘空间;需执行alter table ... compression='zlib', row_format=dynamic, key_block_size=8等显式重建操作,并满足innodb_file_per_table=on、row_format为dynamic/compressed、无全文索引、非临时表四项前提。

ALTER TABLE 启用页压缩必须搭配重建才能释放空间
只执行 ALTER TABLE tbl_name COMPRESSION='zlib' 不会回收磁盘空间——InnoDB 仍保留原有.ibd文件大小,操作系统看不到任何释放。真正释放空间必须触发表重建,哪怕只是“原地重建”。
- 推荐写法:
ALTER TABLE tbl_name COMPRESSION='zlib', ROW_FORMAT=DYNAMIC, KEY_BLOCK_SIZE=8(MySQL 8.0.20+) - 等效但更明确的写法:
ALTER TABLE tbl_name COMPRESSION='zlib' ALGORITHM=INPLACE, LOCK=NONE(需满足前提,否则自动降级为 COPY) - 避免用
OPTIMIZE TABLE:对已启用COMPRESSION的表执行该命令,不仅冗余,还可能因隐式重建触发锁表或失败
执行前必须验证的四个硬性前提
缺一不可,否则 ALTER TABLE ... COMPRESSION 会直接报错,常见错误如 ERROR 1030 (HY000): Got error -1 from storage engine 或 ERROR 1118 (42000): Row size too large。
-
innodb_file_per_table必须为ON(检查:SELECT @@innodb_file_per_table) - 表必须使用
ROW_FORMAT=DYNAMIC或COMPRESSED(查SHOW CREATE TABLE tbl_name;若为COMPACT,先执行ALTER TABLE tbl_name ROW_FORMAT=DYNAMIC) - 不能含
FULLTEXT索引(删掉再重建,或改用外部搜索引擎) - 不能是
TEMPORARY表,且表名不能带特殊字符或引号包裹(如`log_2026`要写成log_2026)
哪些表值得压缩?哪些绝对不要碰?
压缩不是万能药,收益和风险高度依赖访问模式与数据特征。
- 适合压:历史日志表、归档表、JSON/TEXT 占比 >30% 的大表(百万行+),读多写少,压缩率常达 40%–70%
- 不适合压:高频写入的订单表、用户行为流水表(CPU 解压开销会拖慢写入)、
BLOB主导的表(压缩率低,徒增 CPU)、小表( - 特别注意:压缩后加索引、新增列、大批量
INSERT可能触发Row size too large错误——因为压缩页内单行实际存储结构变复杂,建议压前留 10%–15% 行宽余量
重建过程中的锁与资源影响
MySQL 8.0 默认尝试 ALGORITHM=INPLACE,但能否真正无锁取决于是否满足所有在线 DDL 条件。一旦不满足,就会回退到 COPY 模式,全程锁表。
- 关键判断点:查
information_schema.INNODB_TRX和SHOW PROCESSLIST,确认没有长事务阻塞 - 内存压力:重建期间会额外占用 buffer pool 和 sort buffer,建议在低峰期操作,监控
innodb_buffer_pool_pages_free - 磁盘 IO:临时需要双倍空间(原表 + 新表),确保磁盘剩余空间 ≥ 当前表
data_length + index_length的 120% - 最稳妥方式:先在从库测试,确认
ALTER耗时与空间释放量,再同步到主库











