做后端开发、DBA的同学,大概率都遇到过这样的困境:数据库磁盘告急,日志表、历史归档表越存越大,扩容成本高不说,还拖慢IO性能;备份耗时越来越久,甚至影响业务正常运行。
其实不用急着扩容,MySQL自带的压缩表功能,就能轻松解决这个问题,并且以CPU小幅开销,换磁盘空间大幅节省,最高能省70%,还能间接提升IO效率。
一、先搞懂:MySQL压缩表到底是什么
简单说,MySQL压缩表就是通过调整KEY_BLOCK_SIZE大小(可选1、2、、4/8/16)压缩表或特定算法(如zlib、lz4、zstd)压缩页,对表中的数据和索引进行无损压缩,减少磁盘存储占用的一种表优化方式。
核心原理很简单:数据库中的数据(尤其是文本、JSON、日志类数据)存在大量重复序列,压缩算法会找到这些重复序列并进行编码,存储时只保留一份编码信息,读取时再解码还原,全程不丢失任何数据。
1. 主要特点
MySQL的表进行压缩具备如下主要特点:
2. 适合压缩的表
不是所有表都适合压缩,如果出现数据库服务器磁盘空间不足且不宜扩容的情况下,优先压缩这些表:
3. 不适合压缩的表
有些表强行压缩,会导致性能下降,甚至影响后续的写入(新增数据或加索引等会报错),例如下列这些表:
如果处理不当,会出现如下错误:
ERROR 1118 (42000): Row size too large. The maximum row size for the used table type, not counting blobs, is 65535.
This includes storage overhead, so the actual maximum row size is less.或者
ERROR 1030 (HY000): Got error -1 from storage engine文件格式如果是老的格式(老版本物理方式原地升级),则可能会报如下错误:
ERROR 1478 (HY000): InnoDB table 'db.tbl' has row_format=COMPRESSED but the innodb_file_format is Antelope.
Support for COMPRESSED row format requires innodb_file_format=Barracuda.二、 实操案例
1. 表行格式压缩
本次在MySQL5.7中选取一张超过1kw的表(tb2)

压缩前,磁盘空间占用632M

查看当前表的行格式:
show table status like 'tb2';
对该表进行压缩
alter table tb2 row_format='compressed';压缩后,空间降至232M

2. 页压缩
MySQL8.0 中选取一张表,压缩前占用空间68M


通过页压缩方式处理:
mysql> alter table orders COMPRESSION='zlib', ALGORITHM = INPLACE, LOCK = NONE;执行完空间如下:

可以看出,空间并没有降低,主要原因是该命令只修改了表的元数据,仅对后续新增的数据启用压缩,而不会压缩表中已有的存量数据,需要重建表来压缩存量数据。
因此进行优化(重建)处理:
mysql> alter table orders engine =innodb;
重建后大小如下:

3. 压缩前后空间对比
压缩率是与当前表中存储的数据及压缩方式有关,本文中2个案例的压缩率如下:
状态 | 压缩前占用(MB) | 压缩后占用(MB) | 压缩率 |
|---|---|---|---|
行格式压缩 | 632 | 232 | 63.29% |
页压缩(zlib) | 68 | 52 | 23.53% |
三、总结
MySQL压缩表,是以CPU小幅开销,换磁盘空间大幅节省的实用优化手段,尤其适合日志表、归档表等读多写少的大表,最高可省70%存储空间,还能减少IO压力、缩短备份时间。核心记住3点:选对场景(读多写少大表)、选对方式(8.0+优先页压缩)、避开坑点(不盲目压缩高并发表)。
你在使用MySQL压缩表时,踩过哪些坑?或者有更好的优化技巧?欢迎在留言区交流。