InnoDB表压缩调优实战指南
这段文档 17.9.1.3 “Tuning Compression for InnoDB Tables” 是关于 如何调优 InnoDB 表压缩性能 的高级指南。它不再讲“怎么创建压缩表”,而是深入探讨:
❓ 哪些表适合压缩?
❓ 用多大的压缩页(KEY_BLOCK_SIZE
)最合适?
❓ 压缩对 OLTP 和数据仓库场景有何影响?
❓ 应该在数据库压缩,还是在应用层压缩?
❓ 如何测试和判断压缩是否有效?
我们来逐部分解析,用 通俗语言 + 实战视角 帮你彻底理解。
🧭 一、核心思想:压缩不是万能的,要“调优”
“Most often, the internal optimizations … ensure that the system runs well with compressed data. However, because the efficiency of compression depends on the nature of your data, you can make decisions that affect performance.”
📌 重点:MySQL 内部已经做了很多优化,但最终效果取决于你的数据和负载。所以你需要:
- 选对表(哪些表压缩收益高)
- 选对页大小(
KEY_BLOCK_SIZE=8
还是4
?) - 评估负载类型(读多?写多?OLTP?DWH?)
- 调整缓冲池大小(内存够不够?)
🔍 二、什么时候该用压缩?(When to Use Compression)
✅ 适合压缩的场景:
特征 | 说明 |
---|---|
读远多于写 | 查询频繁,DML(INSERT/UPDATE/DELETE)很少 → 压缩失败少 |
包含字符串字段 | CHAR , VARCHAR , TEXT , BLOB → 文本重复多,压缩率高 |
I/O 瓶颈,CPU 充裕 | 磁盘慢,CPU 快 → 用 CPU 换 I/O,提升整体性能 |
❌ 不适合压缩的场景:
特征 | 说明 |
---|---|
写密集型(OLTP 写多) | 频繁 UPDATE → 需要频繁“解压 → 修改 → 重压缩” → 性能下降 |
二进制数据为主 | 整数、浮点数、已压缩的图片(如 JPEG)→ 很难再压缩 |
高度随机的数据 | 没有重复模式 → 压缩无效 |
📌 关键结论:
压缩最适合 数据仓库(DWH) 或 只读/读多写少的归档表。
📊 三、如何判断某张表是否值得压缩?
方法 1:用 gzip
预估压缩率(快速估算)
# 对未压缩的 .ibd 文件进行 gzip 压缩
gzip -c big_table.ibd | wc -c
- 如果
.ibd
文件能被gzip
压缩 50% 以上 → 数据有压缩潜力 - 但注意:MySQL 压缩率通常低于
gzip
,因为它是按页(16KB)压缩,不能跨页找重复
📌 所以:gzip
压缩率 60% → MySQL 实际可能只有 30%~40%
方法 2:真实测试(推荐)
文档给了一个完整实验脚本,我们简化一下:
-- 1. 创建一个大表(模拟真实数据)
CREATE TABLE big_table AS SELECT * FROM information_schema.columns;
-- 多次插入,造数据
INSERT INTO big_table SELECT * FROM big_table; -- 重复几次-- 2. 创建压缩表(KEY_BLOCK_SIZE=4)
CREATE TABLE big_table_cmp LIKE big_table;
ALTER TABLE big_table_cmp KEY_BLOCK_SIZE=4 ROW_FORMAT=COMPRESSED;-- 3. 导入数据
INSERT INTO big_table_cmp SELECT * FROM big_table;-- 4. 比较文件大小
-- 在 shell 中执行:
\! ls -lh data/test/big_table.ibd
\! ls -lh data/test/big_table_cmp.ibd
✅ 如果压缩表 .ibd
文件明显更小(比如 30% 以上),说明压缩有效。
📈 四、如何监控压缩是否“成功”?
MySQL 提供了两个系统表来监控压缩行为:
1. INNODB_CMP
—— 全局压缩统计
SELECT * FROM INFORMATION_SCHEMA.INNODB_CMP;
关键字段:
COMPRESS_OPS
: 压缩操作总次数COMPRESS_OPS_OK
: 成功压缩次数COMPRESS_TIME
: 压缩耗时(微秒)UNCOMPRESS_TIME
: 解压耗时
📌 判断标准:
如果
COMPRESS_OPS_OK / COMPRESS_OPS > 90%
→ 压缩效率高,适合继续使用
如果失败率高(< 50%)→ 说明频繁“压缩失败”,需要调整参数。
2. INNODB_CMP_PER_INDEX
—— 按索引监控(更细粒度)
-- 先启用(性能开销大,仅测试时开启)
SET GLOBAL innodb_cmp_per_index_enabled = ON;-- 查看某个表的每个索引压缩情况
SELECT * FROM INFORMATION_SCHEMA.INNODB_CMP_PER_INDEX
WHERE table_name = 'big_table_cmp';
📌 用途:
- 找出哪个索引压缩失败最多
- 判断是否要调整
KEY_BLOCK_SIZE
💡 五、数据库压缩 vs 应用层压缩
方式 | 优点 | 缺点 | 适用场景 |
---|---|---|---|
数据库压缩 | ✅ 自动、透明 ✅ 所有索引都压缩 ✅ 查询仍可用索引 | ❌ 压缩单位是页(16KB) ❌ 写操作开销大 | 大多数场景推荐 |
应用层压缩 | ✅ 可选择性压缩某些字段 ✅ 压缩 CPU 在客户端 | ❌ 不能用索引查询压缩字段 ❌ 存储的是二进制 blob,难维护 | 特定字段(如日志内容) |
两者都用 | ❌ 不推荐! 双重压缩浪费 CPU,几乎无额外收益 | —— | 避免 |
📌 结论:
选一种方式即可。大多数情况下,直接在数据库启用压缩更简单、更高效。
⚙️ 六、负载类型对压缩的影响
负载类型 | 压缩表现 | 建议 |
---|---|---|
只读 / 读多写少(DWH) | ✅ 极佳 几乎不涉及“重压缩” | 强烈推荐压缩 |
OLTP(频繁 UPDATE) | ⚠️ 可能变慢 UPDATE → 解压 → 改 → 重压缩 → 可能失败 | 谨慎使用,测试后再上线 |
INSERT 多(自增主键) | ✅ 较好 新数据直接压缩写入 | 推荐压缩 |
DELETE 多 | ✅ 较好 InnoDB 可在压缩页上“标记删除” | 可接受 |
📌 关键机制:
- InnoDB 使用 “修改日志”(modification log) 在压缩页内记录小修改
- 当修改太多,日志满了 → 必须“解压 → 重组织 → 重压缩”
- 这个过程叫 “压缩失败”(compression failure),很耗 CPU
📏 七、如何选择 KEY_BLOCK_SIZE
(压缩页大小)?
KEY_BLOCK_SIZE | 适用场景 | 说明 |
---|---|---|
8 (8KB) | ✅ 大多数场景 | 安全、平衡,推荐首选 |
4 (4KB) | ✅ 高压缩需求 | 更小,但可能增加压缩失败 |
2 (2KB) | ⚠️ 极端情况 | 压缩率高,但性能可能下降 |
16 (16KB) | ❌ 一般不推荐 | 压缩率极低,除非有大量 BLOB |
📌 重要规则:
KEY_BLOCK_SIZE
必须 大于最大行大小,否则插入会失败。
- InnoDB 最大行大小 ≈ 8KB
- 所以
KEY_BLOCK_SIZE=8
是最安全的选择
🧠 八、内存与缓冲池(Buffer Pool)的影响
“a configuration with more memory … tends to run better when using compressed tables”
📌 关键点:
- 每个压缩页在内存中会有两个副本:
- 压缩版(占用小)
- 解压版(16KB,用于修改)
- Buffer Pool 需要同时缓存两者
- 如果内存不足 → 频繁换入换出 → 性能下降
✅ 建议:
使用压缩表时,Buffer Pool 要比平时更大,否则可能得不偿失。
✅ 总结:调优压缩的 5 大步骤
步骤 | 操作 |
---|---|
1️⃣ 选表 | 优先压缩:读多写少、含文本、归档表 |
2️⃣ 测试压缩率 | 用 gzip 或创建压缩表测试 .ibd 大小 |
3️⃣ 监控压缩效果 | 查询 INNODB_CMP ,看 COMPRESS_OPS_OK 比例 |
4️⃣ 选页大小 | 优先 KEY_BLOCK_SIZE=8 ,再试 4 |
5️⃣ 评估资源 | 确保 CPU 和内存(Buffer Pool)足够 |
🛠️ 实战建议
-- 1. 开启压缩支持
SET GLOBAL innodb_file_per_table = ON;-- 2. 创建压缩表(推荐配置)
CREATE TABLE archive_logs (id BIGINT AUTO_INCREMENT PRIMARY KEY,message TEXT,created_at DATETIME
) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;-- 3. 上线后监控
SELECT COMPRESS_OPS, COMPRESS_OPS_OK, ROUND(COMPRESS_OPS_OK/COMPRESS_OPS*100, 2) AS success_rate
FROM INFORMATION_SCHEMA.INNODB_CMP;
📌 最终结论
压缩不是“开了就快”,而是一种 用 CPU 换 I/O 和存储空间 的权衡。
✅ 推荐使用场景:
- 数据仓库(DWH)
- 日志归档表
- 只读报表库
- 存储成本敏感 + I/O 瓶颈
❌ 不推荐场景:
- 高频 UPDATE 的核心交易表
- 已压缩的二进制数据
- 内存严重不足的服务器
如果你有具体的表结构或业务场景,我可以帮你分析:这张表值不值得压缩?该用 KEY_BLOCK_SIZE=8
还是 4
?