MySQL 中的压缩技术
为什么要有这篇文章?
MySQL 中数据压缩技术主要有三种:表压缩,页压缩,列压缩。
在互联网上,关于页压缩的源码解析文章比较多,但是关于表压缩,列压缩的源码解析的文章处于空白状态,没有相关资料,这就为一些对压缩技术比较感兴趣的同学提出了一些挑战。
本文旨在通过对表压缩,页压缩,列压缩的源码进行解析,同时做出使用上的说明,以填补这部分的空白。
1. 综述
数据压缩可以减少存储空间,降低存储成本,增加 IO 效率,是降低数据库整体使用成本的重要手段,MySQL 目前具备的压缩能力,包括 InnoDB 存储引擎层提供的 表数据的压缩,以及在 Server 层实现的 binlog 日志压缩两种。
MySQL 中有一个分支 MyRocks 对压缩的支持比较多 IO 也比较优秀,被 Facebook 大规模使用,本文不做重点分析,对 MyRocks 感兴趣可以参考网易 MyRocks 使用和优化。
本文主要介绍 MySQL 中 InnoDB 存储引擎层的压缩,本文所有代码基于 MySQL 8.0.28。
1.1 MySQL 压缩要解决的问题
笔者认为,MySQL 的数据压缩要解决两个问题,第一个问题是通过压缩把数据需要的存储空间减少;第二个问题是对压缩后剩余空间的利用。
MySQL 中的表压缩解决第一个问题使用的方法是通过 zlib 压缩算法提供的接口,通过 Zlib 算法的压缩以及解压使得数据占有的存储空间减少;通过 KEY_BLOCK_SIZE 值的设置,如果成功压缩,就可以把一个页面中 KEY_BLOCK_SIZE 之外的空间通过 MySQL 的调度得以使用。
MySQL 中的页压缩解决第一个问题的方法是通过 zlib 以及 lz4 压缩算法提供的接口来实现,一个 MySQL 页面可以占用更少的操作系统页面;通过操作系统的 punching hole 功能把剩余空间得以调度以及使用。
2 MySQL 中的表压缩
本节主要包括两部分:表压缩的使用与表压缩的代码实现。
2.1 表压缩的使用
2.1.1 如何创建一个压缩表
在 file_per_table 的表空间或者 general 表空间里,可以使用表压缩,系统表不支持对表级别的压缩;用户在设置好 innodb_file_format 之后(仅支持 Barracuda ),再把 ROW_FORMAT (COMPRESSED)与 KEY_BLOCK_SIZE 都设置为对应的值,可以启用表压缩。
file_per_table space 创建压缩表:
mysql> SET GLOBAL innodb_file_per_table=1;
mysql> ## 5.7 设置, 8.0 取消此参数,5.7 默认值 Barracuda
mysql> SET GLOBAL innodb_file_format=Barracuda;
mysql> CREATE TABLE t1 (c1 INT PRIMARY KEY)
mysql> ROW_FORMAT=COMPRESSED KEY_BLOCK_SIZE=8;