迁移BLOB数据必须先启用innodb_file_per_table,再配合ROW_FORMAT=COMPRESSED和KEY_BLOCK_SIZE重建表,否则压缩无效且无法释放磁盘空间。

直接结论:迁移大字段 BLOB 数据时,必须先启用 innodb_file_per_table,再配合 ROW_FORMAT=COMPRESSED 和 KEY_BLOCK_SIZE 重建表;否则压缩无效,且无法真正释放磁盘空间。
为什么迁移前必须确认独立表空间
MySQL 的 InnoDB 默认可能使用共享表空间(ibdata1),而 ROW_FORMAT=COMPRESSED 压缩只对独立表空间生效。即使你执行了 ALTER TABLE ... ROW_FORMAT=COMPRESSED,数据仍会写入共享表空间,不压缩、不瘦身、不可回收空间。
检查方式:
SHOW VARIABLES LIKE 'innodb_file_per_table';
若返回 OFF,需在 my.cnf 中设置并重启:
innodb_file_per_table = ON
注意:该参数只影响新创建的表,已有表需重建才能迁入独立表空间。
迁移时如何安全启用 BLOB 字段压缩
不是所有 BLOB 字段都适合直接开压缩——尤其是频繁更新、单条超大(>16KB)或含加密/已压缩内容的字段。压缩效果取决于原始数据冗余度,盲目开启反而增加 CPU 开销且无收益。
实操建议:
- 先用
SELECT AVG(length(col)), STDDEV(length(col)) FROM tbl WHERE col IS NOT NULL;粗估 BLOB 大小分布,排除已高度压缩(如 JPEG、ZIP、Protobuf)的列 - 对中等大小(2KB–50KB)、文本类(JSON/XML/序列化对象)BLOB 列优先尝试
- 建新表时显式指定压缩参数,而非仅靠
ALTER TABLE修改现有表:
CREATETABLE tbl_compressed AS SELECT id, UNCOMPRESS(COMPRESS(blob_col)) AS blob_col, other_cols FROM tbl_original; ALTERTABLE tbl_compressed ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;
这样可避免原表锁死过久,也绕过旧表格式残留问题。
KEY_BLOCK_SIZE 设多少才不翻车
KEY_BLOCK_SIZE 不是越小越好。它定义压缩页大小(单位 KB),常见值为 1、2、4、8、16。但实际生效受底层文件系统块大小和索引键长度限制:
- 若设为
1或2,而主键或二级索引键太长(比如含VARCHAR(255)+utf8mb4),建表会直接报错ERROR 1071 (42000): Specified key was too long - SSD 场景推荐从
8起步;HDD 可试4;不要低于4,除非确认索引极短且数据极稀疏 - 压缩失败时(如页内无法塞下解压后数据),InnoDB 会退回到未压缩页存储,导致“伪压缩”——磁盘没省,CPU 白耗
验证是否真压缩成功:
SELECT page_size, compressed_size FROM information_schema.INNODB_CMP_PER_INDEX WHERE database_name='your_db' AND table_name='your_table';
若 compressed_size 持续为 0,说明压缩未触发,需检查 KEY_BLOCK_SIZE 是否被忽略或数据本身不可压。
应用层解压逻辑不能漏掉
启用 ROW_FORMAT=COMPRESSED 后,MySQL 自动处理读写时的压缩/解压,但有例外:
- 使用
mysqldump导出时,默认不识别压缩页,导出会还原为未压缩数据,迁移后体积暴涨 - 备份工具如
Percona XtraBackup支持压缩页感知,但需加--compress参数并确认版本兼容性(5.7+ 更稳) - JDBC 连接若启用了
useCompression=true,与服务端压缩叠加可能导致 double-compress,解压失败抛java.io.IOException: Not in GZIP format
最稳妥的迁移路径是:停写 → 创建新压缩表 → 用 INSERT INTO ... SELECT 搬数据 → 校验 CRC32(UNCOMPRESS(blob_col)) 一致性 → 切换应用指向新表 → 删除旧表。
真正容易被忽略的是:压缩表的 information_schema.TABLES.data_length 显示的是压缩后大小,但 buffer_pool 里仍要缓存解压后的完整页——内存压力没减少,只是磁盘和 I/O 降了。别以为开了压缩就万事大吉。


















