不能。ROW_FORMAT=COMPRESSED 不支持直接在已有表上修改,必须通过 ALTER TABLE 重建表并显式指定 KEY_BLOCK_SIZE 和 ROW_FORMAT 才能生效,且需满足 innodb_file_per_table=ON、表为独立表空间等前提条件。
ROW_FORMAT=COMPRESSED 能不能在已有表上直接改?
不能。mysql 5.7+ 中,row_format=compressed 只支持 innodb_file_per_table=on 且表使用独立表空间(.ibd 文件)时,在 create table 或 alter table ... row_format=compressed 时生效;但前提是表引擎是 innodb、未启用 innodb_strict_mode(或严格模式下需同时指定 key_block_size),否则会静默退回到 row_format=dynamic。
- 常见错误现象:
ALTER TABLE t1 ROW_FORMAT=COMPRESSED;执行成功,但SHOW CREATE TABLE t1;仍显示ROW_FORMAT=Dynamic - 根本原因:InnoDB 在严格模式下要求
COMPRESSED必须搭配KEY_BLOCK_SIZE(如KEY_BLOCK_SIZE=8),否则忽略该设置 - 兼容性注意:MySQL 8.0.30+ 已开始标记
ROW_FORMAT=COMPRESSED为废弃(deprecated),新项目建议避免使用
怎么安全地把普通表转成 COMPRESSED 行格式?
必须重建表,且要显式指定 KEY_BLOCK_SIZE 和 ROW_FORMAT,不能只改一个参数。
- 先确认当前配置:
SELECT @@innodb_file_per_table, @@innodb_strict_mode;—— 两者都应为ON - 检查表是否已用独立表空间:
SELECT NAME, FILE_FORMAT, ROW_FORMAT FROM INFORMATION_SCHEMA.INNODB_SYS_TABLES WHERE NAME LIKE 'db_name/t1';,确保FILE_FORMAT是Barracuda - 执行重建:
ALTER TABLE t1 ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=4;(可选值:1/2/4/8/16,单位 KB;值越小压缩率越高,CPU 开销越大) - 验证结果:
SHOW TABLE STATUS LIKE 't1';查看Row_format字段,同时检查Data_length是否明显下降
为什么改了 ROW_FORMAT=COMPRESSED 却没节省空间?
压缩效果高度依赖数据特征和页内填充率,不是设了就一定“变小”。
- 典型场景失效:字段全是短字符串(如 UUID、固定长度 char)、大量 NULL 值、或行本身远小于 16KB 页——InnoDB 不会对单行单独压缩,而是对整个 16KB 数据页做页级 LZB1 压缩
- 性能影响:写入时需额外压缩计算,高并发写入可能增加 CPU 压力;读取时解压也耗 CPU,尤其配合
buffer_pool频繁换入换出时 - 容易踩的坑:
KEY_BLOCK_SIZE=1看似压缩最强,但会导致页内能存的行数锐减,反而引发更多页分裂和 B+ 树层级升高,查询变慢
有没有更现代的替代方案?
有。MySQL 5.7 引入的 page_compression(配合 innodb_page_compression_algorithm)比 ROW_FORMAT=COMPRESSED 更灵活,且 8.0 支持在线开启。
- 前提:表必须是独立表空间 +
innodb_file_per_table=ON+innodb_file_format=Barracuda - 启用方式:
ALTER TABLE t1 COMPRESSION='zlib';(支持zlib/lz4/zstd) - 优势:无需指定
KEY_BLOCK_SIZE,压缩算法可动态选,且支持在线 DDL(ALGORITHM=INPLACE) - 注意点:压缩仅对新写入页生效,老页不会自动重压;需配合
OPTIMIZE TABLE或等自然页更新
KEY_BLOCK_SIZE 的取值和压缩算法选择,得看你的数据冷热分布、读写比例、以及是否有空闲 CPU 资源——这些没法靠一个 ALTER 命令自动判断。

















