innodb不支持系统表空间(如ibdata1)页面压缩,仅支持独立表空间(.ibd)的页压缩,需同时满足innodb_file_per_table=on、row_format=compressed及key_block_size设置。

innodb_page_compressed 是个不存在的配置项——MySQL 官方从未提供过这个参数,也不支持对系统表空间(如 ibdata1)开启页面级压缩。
你查到的这个词,大概率是混淆了几个概念:ROW_FORMAT=COMPRESSED(表级)、KEY_BLOCK_SIZE(页压缩大小)、以及错误拼写的内部变量名。真正能用的、有文档支撑的,只有针对独立表空间(.ibd 文件) 的压缩能力。
怎么给 InnoDB 表启用页压缩(只对 .ibd 有效)
压缩必须满足三个硬性前提,缺一不可:
-
innodb_file_per_table = ON(必须开启,否则表建在共享表空间里,压不了) -
innodb_file_format = BARRACUDA(5.7.7+ 已默认,老版本需显式设) - 表使用
ROW_FORMAT=COMPRESSED+KEY_BLOCK_SIZE
示例(新建表):
CREATE TABLE logs ( id BIGINT PRIMARY KEY, content TEXT ) ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4;
已有表转换(会锁表、重建,慎在线上执行):
ALTER TABLE logs ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4;
为什么系统表空间(ibdata1)不能压缩
这是 InnoDB 的设计限制,不是配置没开对:
- 系统表空间包含数据字典、undo log、change buffer 等核心元数据,结构复杂且需随机访问,压缩会破坏一致性保障
- 官方明确说明:“Pages in the system tablespace are not compressed”(见 MySQL 8.0 Reference Manual)
- 即使你强行在配置里写
innodb_page_compressed=ON,MySQL 启动时会直接忽略或报错
临时表空间(ibtmp1)、通用表空间(CREATE TABLESPACE ... ADD DATAFILE)同样不支持压缩。
KEY_BLOCK_SIZE 怎么选?常见踩坑点
它不是“压缩比”,而是你希望压缩后每页占用的物理大小(单位 KB),可选值只有 1、2、4、8(16 等价于不压缩)。
- 值越小,I/O 越少,但 CPU 开销越大;若压缩失败(比如一行数据压缩后仍超
KEY_BLOCK_SIZE),InnoDB 会自动分配额外空间,反而导致页碎片和性能下降 -
KEY_BLOCK_SIZE=1在绝大多数业务场景下不可用——索引前缀长度、行头开销等会让实际可用空间远小于 1KB - 验证是否生效,别只看
SHOW CREATE TABLE,要查INFORMATION_SCHEMA.INNODB_TABLES中的COMPRESSION列(值为ZLIB才算真启用了)
替代方案:系统表空间太大,还能做什么
既然不能压缩,就只能换思路:
- 把大表迁出系统表空间:
SET GLOBAL innodb_file_per_table = ON后重建表(ALTER TABLE ... ENGINE=InnoDB) - 清理 undo log:
innodb_undo_log_truncate = ON(配合innodb_max_undo_log_size) - 收缩系统表空间本身不可行,但可以导出+重建整个实例(
mysqldump或mydumper+ 重装) - 监控
DATA_FREE值:如果SHOW TABLE STATUS里某张 MyISAM 表的Data_free很高,那是可以OPTIMIZE TABLE回收的——但这和 InnoDB 系统表空间无关
真正的难点在于:系统表空间一旦膨胀,就没有“在线缩容”这条路。所有所谓“压缩系统表空间”的操作,本质都是绕开它,而不是动它。











