在pg中,行不能跨页存储,为了存储更大的行,pg使用Toast技术将行压缩成更小的块。关于Toast我在之前的文章有介绍过,pg使用固定的页面大小(通常为8kb),并且不允许跨页存储。因此,单行不能直接存储很大的字段值。为了克服这个限制,大字段被压缩或分解成多个物理行。
Toast的压缩采用lz字典压缩算法,
源码可见:
https://git.postgresql.org/gitweb/?p=postgresql.git;a=blob;f=src/common/pg_lzcompress.c
感兴趣的可以看看。
在13.0以前,我们没办法选择如何压缩数据,因为只有一种算法可以压缩PostgreSQL中的数据,那就是pglz。但是14.0版本提供了可配置的lz4 TOAST压缩特性,将会允许我们选用LZ4作为Toast的压缩算法。
commit见:
https://git.postgresql.org/gitweb/?p=postgresql.git;a=commit;h=bbe0a81db69bd10bd166907c3701492a29aca294
接下来我们来看一下这个特性。注:接下来演示的内容在centos7系统下操作。
1、下载14.0版本的源码,执行./configure --help | grep LZ4, 可以看到该版本提供了lz4支持,参数是--with-lz4
./configure --help | grep LZ4
--with-lz4 build with LZ4 support
LZ4_CFLAGS C compiler flags for LZ4, overriding pkg-config
LZ4_LIBS linker flags for LZ4, overriding pkg-config
复制
2、使用--with-lz4参数进行配置。
sudo ./configure --prefix=/usr/local/postgresql --with-lz4
复制
报错:
configure: error: Package requirements (liblz4) were not met:
No package 'liblz4' found
原因是缺少liblz4依赖包。
3、安装liblz4相关包。
sudo yum install epel-release
yum install lz4
sudo yum install lz4-devel
复制
4、编译安装。
sudo make world ; sudo make install
复制
5、添加用户和组。
sudo useradd postgres
sudo groupadd postgres
# 修改postgres用户密码
sudo passwd postgres
复制
6、创建data目录,并修改权限。
sudo mkdir usr/local/postgresql/data
sudo chown postgres usr/local/postgresql/data
sudo chgrp postgres usr/local/postgresql/data
复制
7、初始化集群。
su postgres
/usr/local/postgresql/bin/initdb -D usr/local/postgresql/data
复制
8、启动服务器。
usr/local/postgresql/bin/pg_ctl -D usr/local/postgresql/data -l usr/local/postgresql/data/logfile start
复制
9、登陆。
psql -U postgres -h 127.0.01 -p 5432 -d postgres
复制
10、安装好带有zl4支持的14.0版本后,让我们创建两个表:一个使用默认压缩,另一个使用新的LZ4压缩:
create table t1 ( a text );
create table t2 ( a text compression LZ4 );
复制
可以看到t1和t2表的TOAST策略都为extended, 即允许压缩和行外存储。但是t1表的Compression算法是pglz,t2表的compression是lz4。
11、接下来,我们分别往两张表中新增一些数据。
postgres=# \timing on
Timing is on.
postgres=# insert into t1(a) select lpad('a',1000000,'a') from generate_series(1,1000);
INSERT 0 1000
Time: 5488.684 ms (00:05.489)
postgres=# insert into t2(a) select lpad('a',1000000,'a') from generate_series(1,1000);
INSERT 0 1000
Time: 595.999 ms
复制
可以发现t2插入更快。来看下两张表的toast表。
postgres=# select oid,relname from pg_class where oid in (select reltoastrelid from pg_class where relname in ('t1','t2') );
oid | relname
-------+----------------
16397 | pg_toast_16394
16402 | pg_toast_16399
(2 rows)
Time: 0.606 ms
postgres=# select pg_size_pretty(pg_relation_size('pg_toast.pg_toast_16394'));
pg_size_pretty
----------------
12 MB
(1 row)
Time: 0.349 ms
postgres=# select pg_size_pretty(pg_relation_size('pg_toast.pg_toast_16399'));
pg_size_pretty
----------------
4000 kB
(1 row)
postgres=# select count(*) from pg_toast.pg_toast_16394;
count
-------
6000
(1 row)
Time: 0.894 ms
postgres=# select count(*) from pg_toast.pg_toast_16399;
count
-------
2000
(1 row)
Time: 0.463 ms
复制
可以看到lz4不仅速度更快,而且压缩效果也更好。
12、其他用法。
查看默认的压缩策略。
postgres=# show default_toast_compression ;
default_toast_compression
---------------------------
pglz
(1 row)
Time: 0.156 ms
复制
修改默认压缩策略。
postgres=# show default_toast_compression ;
default_toast_compression
---------------------------
pglz
(1 row)
Time: 0.156 ms
postgres=# SET default_toast_compression TO lz4;
SET
Time: 0.163 ms
postgres=# show default_toast_compression ;
default_toast_compression
---------------------------
lz4
(1 row)
Time: 0.163 ms
复制
修改具体表的某个列的压缩策略。
postgres=# ALTER TABLE t2 ALTER COLUMN a SET COMPRESSION pglz;
ALTER TABLE
Time: 4.005 ms
postgres=# \d+ t2
Table "public.t2"
Column | Type | Collation | Nullable | Default | Storage | Compression | Stats target | Description
--------+------+-----------+----------+---------+----------+-------------+--------------+-------------
a | text | | | | extended | pglz | |
Access method: heap
postgres=#
复制
其他
其实压缩是一个比较宽范的话题,可以从好几个维度去讨论。
比如上文我们讲的列压缩技术Toast,也可以是文件系统级别的zfs压缩,以及TimescaleDB里的时间序列数据压缩(可参见:https://docs.timescale.com/timescaledb/latest/how-to-guides/compression/)等等。
但是对于所有的压缩,其实就是在节省空间与耗费额外的cpu资源之间做权衡。而存储空间通常又是最便宜的资源......所以说压缩不一定就是有益的,要视情况而定。
参考:https://blog.dbi-services.com/postgresql-14-lz4-compression-for-toast/
https://www.enterprisedb.com/blog/configurable-lz4-toast-compression
https://docs.timescale.com/timescaledb/latest/how-to-guides/compression/