mysql如何通过压缩数据减少存储成本_mysql压缩技术应用

5次阅读

InnoDB表级压缩需Barracuda格式+ROW_FORMAT=COMPRESSED+KEY_BLOCK_SIZE,压缩数据页而非整表或列;网络压缩(–compress)不减磁盘空间;字段级压缩用COMPRESS()/UNCOMPRESS()函数。

mysql如何通过压缩数据减少存储成本_mysql压缩技术应用

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 --compressmy.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_cleanerinnodb_adaptive_hash_index 等参数虽不直接影响体积,但会影响压缩页的刷盘效率和缓存命中,间接决定“压缩后是否真快”

压缩不是银弹;它把 CPU 换成磁盘,还可能让随机读变慢。上线前务必在真实数据量和 QPS 下压测 IO 和 CPU 使用率。

text=ZqhQzanResources