MySQL 8.0.20+页压缩需同时满足innodb_file_per_table=ON、ROW_FORMAT=DYNAMIC/COMPRESSED、无FULLTEXT索引及非临时表三项硬性前提,缺一不可;启用COMPRESSION='zlib' KEY_BLOCK_SIZE=8后需验证INFORMATION_SCHEMA.INNODB_TABLES中SPACE_TYPE=Single且ROW_FORMAT=Compressed,并对比磁盘文件大小确认实效。

直接执行 ALTER TABLE ... ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8 是最快方式,但必须满足前提条件,否则会报错或无效。
确认表是否满足压缩前提
页压缩不是“设了就生效”,MySQL 会当场拒绝不合规的请求。先检查三项硬性条件:
-
innodb_file_per_table必须为ON:用SHOW VARIABLES LIKE 'innodb_file_per_table';查;若为OFF,需改配置并重启,已有表还得ALTER TABLE t ENGINE=InnoDB;迁移 - 当前
ROW_FORMAT必须是DYNAMIC或COMPRESSED:查SHOW CREATE TABLE tbl_name;;若为COMPACT或REDUNDANT,得先执行ALTER TABLE tbl_name ROW_FORMAT=DYNAMIC; - 表不能含
FULLTEXT索引,也不能是临时表:否则ALTER TABLE ... COMPRESSION会直接报ERROR 1030 (HY000): Got error -1 from storage engine
执行压缩语句并理解参数含义
满足前提后,一条 DDL 即可完成格式切换与压缩设置:
安装、修复、更新或打包一个基于 Python 和 PyMySQL 实现的 Windows `mysql` 命令。适用于用户希望在 PowerShell/CMD 中输入 `mysql` 时重定向到 Python 实现、需要交互式输入 MySQL 连接信息、需要同步到当前用户本地 bin 目录,或需要将该能力封装成可公开复用的 Codex skill。
ALTER TABLE logs_2025_q1 ROW_FORMAT=DYNAMIC, COMPRESSION='zlib', KEY_BLOCK_SIZE=8;
注意几点:
-
COMPRESSION='zlib'是 MySQL 8.0.20+ 引入的页压缩语法,比旧版ROW_FORMAT=COMPRESSED更明确、更可控;zlib是唯一默认支持的算法,lz4需额外加载插件 -
KEY_BLOCK_SIZE不是“压缩目标大小”,而是引擎尝试压缩到的页尺寸(单位 KB),合法值仅限1、2、4、8、16;8是平衡压缩率与 CPU 开销的常用起点 - 该语句本质是重建表,会锁表(MDL 锁),大表务必避开高峰期;MySQL 8.0.29+ 支持
ALGORITHM=INPLACE,但页压缩仍需拷贝数据,无法真正“在线”
验证压缩是否生效且空间已释放
执行完 DDL 后,别急着走——光改元数据不释放磁盘空间:
- 查物理效果:
SELECT table_name, round(data_length/1024/1024,2) AS size_mb, data_free FROM information_schema.tables WHERE table_schema='your_db' AND table_name='logs_2025_q1';;data_free应显著下降,size_mb也应缩小(文本类表通常压掉 40%–60%) -
OPTIMIZE TABLE对已启用页压缩的表**有害无益**:它会触发二次重建,浪费 I/O 和时间,还可能干扰压缩页布局;MySQL 官方文档明确说明,页压缩表无需也不应再跑OPTIMIZE TABLE - 压缩效果高度依赖数据特征:含大量重复字符串、JSON、HTML 的
TEXT/BLOB字段收益高;纯数字或短VARCHAR(20)可能越压越大(zlib 头开销占比较高)
最容易被忽略的是:压缩后缓冲池内存占用会变高——因为 InnoDB 默认同时缓存压缩页和解压页,若 innodb_buffer_pool_size 不足,反而引发频繁换页和性能抖动。上线前务必观察 INFORMATION_SCHEMA.INNODB_CMPMEM 相关指标。

















