前言
此博客翻译自 富士通 PG官方博客《What is the new LZ4 TOAST compression in PostgreSQL 14, and how fast is it?》
PostgreSQL 14 中引入的新列压缩选项 LZ4 提供了更快的压缩。我们该如何使用它,它的速度有多快?与 TOAST 中现有的 PGLZ 相比,它的压缩速度更快。在这篇博文中,我将描述如何使用此选项,并将其性能与其他压缩方法进行比较。
背景
在 PostgreSQL中,页是存储数据的基本单位,每页的大小默认为 8kB。基本上,一行中的数据不允许跨页存储。但是,某些数据类型具有可变长度,它们可能会超过一页的大小。为了克服这个限制,大字段值被压缩或(和)分解成多个物理行。这种技术被称为 TOAST (The Oversized-Attribute Storage Technique);
默认情况下,只有在表中存在变长列,并且行数据大小超过 TOAST_TUPLE_THRESHOLD(通常为 2 kB)时才会触发 TOAST。首先,数据将被压缩,然后,如果数据仍然太大,它将被离线存储。请注意,如果将列的存储策略指定为 EXTERNAL/PLAIN,则将禁用压缩。
在 PostgreSQL 14 之前,TOAST 仅支持一种压缩算法 - PGLZ,一种 PostgreSQL 内置算法。尽管其他压缩算法可能比 PGLZ 更快或具有更高的压缩率。
但从 PostgreSQL 14 开始,我们有另一种选择:LZ4 压缩——一种以速度著称的无损压缩算法。所以,我们可以期待它有助于提高 TOAST 中压缩和解压的速度。
LZ4怎么用?
为了使用 PostgreSQL14 新增的 LZ4 压缩功能,需要在操作系统中安装 LZ4 相关的库,并在编译打包 PostgreSQL 时指定 --with-lz4 选项。
将 LZ4 设置为默认压缩算法
您可以通过配置 GUC 参数 default_toast_compression 来指定 PostgreSQL 实例中 TOAST 的压缩算法。您也可以修改 postgresql.conf 配置文件或使用 SET 命令仅针对当前客户端连接(会话)更改它。
配置 GUC 参数 default_toast_compression使用 CREATE TABLE 设置列上的压缩算法
我们使用\d+(一个 describe 命令)来显示所有列的压缩算法。如果该列不支持压缩或未指定压缩算法,则 Compression 列中将显示空白。
在上面的例子中,我们看到列 id 不支持压缩,col1 使用 PGLZ,col2 使用 LZ4,而 col3 没有指定压缩算法,因此它将使用默认压缩算法(PGLZ)。
使用 ALTER TABLE 修改列上的压缩算法
可以使用 ALTER TABLE 更改现有列的压缩算法,但请注意,新的压缩算法将仅应用于执行 ALTER TABLE 命令后插入的数据。
使用 ALTER TABLE 修改列上的压缩算法上面我们看到,在我们更改压缩算法之前插入的行中,col1 仍然使用 PGLZ 进行压缩,即使我们将压缩从 PGLZ 更改为 LZ4。
笔记
1、如果从其他表插入数据,例如使用CREATE TABLE ... AS ...,或INSERT INTO ... SELECT ...,插入数据的压缩方法将与原始数据相同。
2、在支持 LZ4 的同时,pg_dump 和 pg_dumpall 还添加了选项 --no-toast-compression,使用时不会转储 TOAST 压缩选项。
性能对比
这里我做了一些测试,比较了LZ4和PGLZ在压缩比和压缩速度方面的对比。作为参考,我添加了未压缩数据的测试结果(指定存储策略为EXTERNAL)。对于未压缩的数据,没有压缩和解压消耗的时间,但相应地,读取和写入数据所花费的时间增加。
准备
测试中使用了以下数据:
1、PostgreSQL 文档(每行一个 HTML 文件);
2、Silesia Corpus 提供的数据,包括:HTML、文本、源代码、可执行的二进制文件、图片;
测试服务器的处理器规格为 Intel® Xeon® Silver 4210 CPU @2.20GHz,10 核/20 线程/2 插槽。
我使用 pgbench 来测量 SQL 执行时间,并使用系统函数 pg_table_size 来检查表大小(注意:在每次测试之前执行命令 VACUMM FULL 以清理数据存储)。
压缩率
PGLZ和LZ4的压缩率都与重复数据有关——重复项越多,压缩率越高。
但是,即使数据大小达到阈值,在 PostgreSQL 评估结果比率不佳的情况下,也不会执行压缩。这是因为压缩不会有效地节省磁盘空间,反而会导致额外的时间和资源来解压缩。
根据PostgreSQL14目前的源码,PGLZ要求至少25%的压缩率,而LZ4只要求压缩数据不大于未压缩数据。
我将使用压缩算法 LZ4 和 PGLZ 的表大小与未压缩算法进行了比较。我们可以看到,在大多数情况下,PULL 的压缩率稍微好一些-。平均而言,PGLZ的压缩率为2.23,LZ4的压缩率为2.07。这意味着与 LZ4 相比,PGLZ 可以节省大约 7% 的磁盘空间。
图 1 - 比较表大小(以 KB 为单位)压缩/解压速度
TOAST 数据在插入/查询时被压缩/解压缩。所以,我执行了一些SQL语句,看看不同压缩算法对压缩/解压速度的影响。
INSERT 语句
首先,我比较了使用 LZ4、使用 PGLZ 和不使用压缩的列中 INSERT 语句的性能。
我看到 LZ4 插入数据的时间比未压缩的略多,而使用 PGLZ 时,插入数据所花费的时间显着增加。平均而言,LZ4 压缩只需要 PGLZ 花费的时间的 20% 左右,LZ4 和 PGLZ在插入方面,有着非常显着的提高。
图 2 - 比较 INSERT 性能SELECT 语句
接下来,我比较了使用相同列压缩设置的 SELECT 语句的性能。
结果是,在查询数据时,LZ4 比PGLZ 减少了20%左右的时间,LZ4 和未压缩的相比没有明显的增加。似乎 LZ4 减压花费的时间已经减少到非常低的水平。
图 3 - 比较 SELECT 性能
16 个客户端的 INSERT 语句
我测试的另一个常见场景,从多个客户端访问数据库 - 在本例中为 16 个客户端。
我发现,如下所示,与 PGLZ 相比,使用 LZ4 的单个大文件(HTML、英文文本、源代码、可执行二进制文件、图片)的压缩性能要快 60% 到 70%,并且在插入多个小文件(PostgreSQL 文档)时也有一个小的改进。
LZ4 与未压缩的相比,还有一个显着的改进,我猜这是因为使用压缩减少了写入磁盘的数据量。
图 4 - 比较 INSERT 性能(16 个客户端)
16 个客户端的 SELECT 语句
然后我测试了 SELECT 语句在多客户端查询场景中的性能。 同样,在大多数情况下,LZ4 的表现优于 PGLZ。
图 5 - 比较 SELECT 性能与(16 个客户端)
字符串函数
最后,我通过使用字符串函数执行 SELECT 和 UPDATE 语句来比较文本处理的速度。
在这种情况下,LZ4 的表现优于 PGLZ。 LZ4 压缩数据在每个函数上花费的时间与未压缩数据几乎相同,这意味着 LZ4 压缩几乎不影响字符串操作速度。
结论
与PGLZ相比,Let 对 TOAST 数据的压缩和解压效率更高,表现出优异的性能——查询速度接近未压缩数据,数据插入速度比PGLZ快80%。当然,在某些场景下会牺牲压缩率,但是如果要提高执行速度,我强烈推荐 LZ4 而不是 PGLZ。
注意,您应该考虑表中的数据是否适合压缩。如果压缩率不好,PostgreSQL 仍然会尝试压缩数据然后放弃。这会造成额外的内存资源浪费,大大影响插入数据的速度。
展望未来
LZ4 压缩 TOAST,压缩和解压性能大大提高。除了 LZ4,还有一些其他优秀的压缩算法,比如 Zstandard。由于支持 Zstandard,用户可以获得比 PGLZ 更好的压缩率。另一个是 LZ4 HC 算法,平均压缩速度是 LZ4 速度的98.5%,但是压缩比 PGLZ 有大幅提升。希望以后的 PostgreSQL 版本可以有更多的压缩算法,让用户可以根据自己的需要自由选择。
除了 TOAST,在其他一些场景中也需要用到压缩。据我所知,目前的开发版本已经支持了 WAL 的LZ4压缩,非常令人兴奋。
*
网友评论