MySQL 表级压缩:InnoDB 的 ROW_FORMAT=COMPRESSED
怎么用
直接结论:InnoDB 支持表级压缩,但仅限于使用
Barracuda文件格式 +
ROW_FORMAT=COMPRESSED,且必须配合
KEY_BLOCK_SIZE设置(如 1、2、4、8、16,单位 KB)。它压缩的是每个数据页(16KB),不是整张表或列。
常见错误是建表时只写
ROW_FORMAT=COMPRESSED却没设
FILE_FORMAT=Barracuda或忽略
innodb_file_per_table=ON—— 这会导致语句静默退化为
ROW_FORMAT=Dynamic,完全不压缩。
innodb_file_format在 MySQL 5.7.7+ 已废弃,实际由
innodb_file_per_table和表空间类型决定;务必确认
SHOW VARIABLES LIKE 'innodb_file_per_table';返回
ON建表示例:
CREATE TABLE t1 (id INT, data TEXT) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;已存在表需重建:
ALTER TABLE t1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;,注意这会锁表并产生临时空间 压缩效果高度依赖数据重复度和长度;短文本或随机二进制(如加密字段)几乎不减小体积,反而因页管理开销略增
MySQL 服务端压缩传输:mysql --compress
和 my.cnf
中的 compress
这个「压缩」跟存储成本无关,只压缩客户端与服务端之间的网络包,节省带宽,不减少磁盘占用。很多人误以为开了它就能省存储,其实完全不影响
.ibd文件大小。
启用方式有两种:
连接时加参数:mysql --compress -u user -p db_name配置文件中设置:
[client]\ncompress=1(注意是
[client]段,不是
[mysqld]) 服务端需支持:MySQL 5.7+ 默认允许,但若
skip-networking=1或启用了
require_secure_transport,可能被禁用 性能影响:CPU 占用略升,延迟在千兆内网可忽略;WAN 环境下对大结果集(如
SELECT * FROM huge_log)有明显提速
列级压缩:用 COMPRESS()
+ UNCOMPRESS()
手动处理 BLOB/TEXT 字段
这是真正可控、按需压缩单个字段的方式,适合存日志、JSON、HTML 等长文本。压缩发生在应用层或 SQL 层,数据以
VARBINARY形式落地,节省磁盘空间明确。
但必须自己管理压缩/解压逻辑,ORM 或查询工具不会自动识别:
插入时压缩:INSERT INTO logs (content) VALUES (COMPRESS('very long string...'));
查询时解压:SELECT UNCOMPRESS(content) FROM logs WHERE id = 1;不能对压缩后的字段建普通索引;若需搜索,得额外存摘要(如
SUBSTR(content, 1, 200))或用生成列 + 虚拟索引 注意返回值:
COMPRESS()失败(如内存不足)返回
NULL,且不报错;建议在应用层加校验 MySQL 8.0.19+ 支持
ZSTD压缩算法(需编译支持),比默认的
zlib压缩率更高、速度更快,但需显式调用
COMPRESS(..., 'zstd')
真正影响存储成本的关键点:别只盯压缩,先看行格式和页利用率
很多用户花时间调
KEY_BLOCK_SIZE,却发现表体积没怎么变——问题往往出在原始数据太稀疏或行太小。InnoDB 压缩是以页为单位的,如果一行就占满一页(比如含多个大
TEXT),压缩无效;反之,若一行只有几十字节,一页能塞上百行,压缩收益才明显。
更值得优先检查的项:
是否用了TEXT/
BLOB导致行溢出?溢出页不参与
COMPRESSED页压缩,它们始终以未压缩形式存在 字符集是否过大?
utf8mb4下一个 emoji 占 4 字节,而
latin1下纯英文字段可省 3/4 空间 —— 压缩前先精简编码更有效 有没有大量
NULL值?InnoDB 对
NULL本身不存数据,但若定义了默认值或频繁
UPDATE设为非 NULL,会引发页分裂和碎片
innodb_page_cleaner和
innodb_adaptive_hash_index等参数虽不直接影响体积,但会影响压缩页的刷盘效率和缓存命中,间接决定“压缩后是否真快”
压缩不是银弹;它把 CPU 换成磁盘,还可能让随机读变慢。上线前务必在真实数据量和 QPS 下压测 IO 和 CPU 使用率。
