PostgreSQL从开始就设计成可以扩展的。因此,加载到数据库的扩展可以像它们被打包在数据库里一样。PostgreSQL源代码的contrib/目录里面有大量这种扩展。该目录下的README文件包含PostgreSQL扩展的相应帮助信息。它们包含转换工具、全文索引、XML工具、额外的数据类型和索引方法等等。PostgreSQL也支持单独开发额外的扩展。
这里重点介绍一下数据预热扩展pg_prewarm。pg_prewarm扩展可以把关系数据预存入操作系统缓冲区或者PostgreSQL缓冲区,从而提高PostgreSQL数据库读取数据的效率。PostgreSQL数据库可以通过两种不同的方式进行数据预热,即:数据的手工预热和数据的自动预热。视频讲解如下:
一、 安装pg_prewarm扩展
在使用数据预热功能之前需要先按照pg_prewarm扩展,下面是具体的安装步骤。
(1)进入PostgreSQL源码目录下的contrib/pg_prewarm目录。
cd postgresql-15.3/contrib/pg_prewarm/
(2)编译并安装pg_prewarm。
make make install
(3)修改postgresql.conf参数文件中的shared_preload_libraries参数。
shared_preload_libraries = 'file_fdw,postgres_fdw,pg_prewarm'
(4)重启PostgreSQL数据库服务器。
(5)创建pg_prewarm扩展。
postgres=# create extension pg_prewarm;
(6)查看pg_prewarm扩展的详细信息。
postgres=# \dx+ pg_prewarm # 输出的信息如下: Objects in extension "pg_prewarm" Object description ------------------------------------------------------- function autoprewarm_dump_now() function autoprewarm_start_worker() function pg_prewarm(regclass,text,text,bigint,bigint) (3 rows) # 从这里的输出信息可以看出,pg_prewarm扩展自动创建了三个与数据预热相关的函数。
二、 数据的手工预热
数据的手工预热主要是通过函数pg_prewarm()完成,下面展示了该函数的申明。
pg_prewarm( regclass, mode text default 'buffer', fork text default 'main', first_block int8 default null, last_block int8 default null) RETURNS int8 # 这里最重要的参数就是第一个参数regclass,它表示要进行预热的表名,函数的返回值是预热块的数量。
下面通过一个具体的示例来演示如何使用pg_prewarm()函数。
(1)创建一张表用于进行测试。
postgres=# create table prewarmtable(pid int,pname varchar(20));
(2)往表中插入5000万条测试数据。
postgres=# insert into prewarmtable select n,'name'||n from generate_series(1,50000000) n;
(3)执行一条简单的查询语句,并查看相应的执行计划。
postgres=# explain (analyze,buffers,timing) select * from prewarmtable; # 输出的信息如下: QUERY PLAN -------------------------------------------------------- Seq Scan on prewarmtable (cost=0.00..808940.56 rows=50010856 width=16) (actual time=0.035..5339.230 rows=50000000 loops=1) Buffers: shared read=308832 Planning: Buffers: shared hit=14 read=7 Planning Time: 0.347 ms Execution Time: 8385.500 ms (6 rows) # 从输出的结果可以看出,此时从磁盘上读取了308832数据块。
(4)再次执行同样的查询语句,并查看相应的执行计划。
postgres=# explain (analyze,buffers,timing) select * from prewarmtable; # 输出的信息如下: QUERY PLAN -------------------------------------------------------- Seq Scan on prewarmtable (cost=0.00..808940.56 rows=50010856 width=16) (actual time=0.035..5304.973 rows=50000000 loops=1) Buffers: shared hit=32 read=308800 Planning Time: 0.030 ms Execution Time: 8351.421 ms (4 rows) # 从输出的结果可以看出,第二次读取数据时有32个数据块被执行了缓存。
(5)重启PostgreSQL数据库服务器,以达到清空缓存的目的。
(6)使用pg_prewarm()函数预热表prewarmtable的数据。
postgres=# select pg_prewarm('prewarmtable'); pg_prewarm ------------ 308832 (1 row)
(7)再次执行同样的查询语句,并查看相应的执行计划。
postgres=# explain (analyze,buffers,timing) select * from prewarmtable; # 输出的信息如下: QUERY PLAN -------------------------------------------------------- Seq Scan on prewarmtable (cost=0.00..808940.56 rows=50010856 width=16) (actual time=0.017..5470.853 rows=50000000 loops=1) Buffers: shared hit=16308 read=292524 Planning: Buffers: shared hit=3 read=3 Planning Time: 0.120 ms Execution Time: 8620.384 ms (6 rows) # 从输出的结果可以看出,由于使用了pg_prewarm()函数预热数据 # 此时读取数据时有16308个数据块被执行了缓存。
三、 数据的自动预热
当pg_prewarm扩展安装配置成功后,PostgreSQL数据库服务器会周期性地把共享内存中的内容记录在一个名为autoprewarm.blocks的文件中,并在数据库服务器重新启动时读取该文件以达到数据预热的目的。文件autoprewarm.blocks默认保存在$PGDATA目录下,如下所示。
[postgres@mydb pgsql]$ pwd /home/postgres/training/pgsql [postgres@mydb pgsql]$ ll data/autoprewarm.blocks -rw------- 1 postgres postgres 425037 ... data/autoprewarm.blocks
下面通过一个简单的测试来验证重启数据库服务器后,数据是否会自动进行预热。
(1)重启PostgreSQL数据库服务器,以达到清空缓存的目的。
(2)执行一条简单的查询语句,并查看相应的执行计划。
postgres=# explain (analyze,buffers,timing) select * from prewarmtable; # 输出的信息如下: QUERY PLAN -------------------------------------------------------- Seq Scan on prewarmtable (cost=0.00..808940.56 rows=50010856 width=16) (actual time=0.026..8544.466 rows=50000000 loops=1) Buffers: shared hit=16191 read=292641 Planning: Buffers: shared hit=18 read=3 Planning Time: 0.461 ms Execution Time: 13426.254 ms (6 rows) # 从输出的结果可以看出 # 此时读取数据时有16191个数据块被执行了自动预热加载到了缓存中。
在默认情况下,pg_prewarm扩展会每隔5分钟将内存中的数据写入文件autoprewarm.blocks中,这是由参数pg_prewarm.autoprewarm_interval决定,如下所示。
postgres=# show pg_prewarm.autoprewarm_interval ; # 输出的信息如下: pg_prewarm.autoprewarm_interval --------------------------------- 5min (1 row)
当重启PostgreSQL数据库服务器时,通过后台进程autoprewarm master将预热数据文件autoprewarm.blocks重新加载到内存中。通过使用ps命令可以看到该进程的信息,如下所示:
[postgres@mydb pgsql]$ ps -ef|grep postgres: postgres 107174 107172 ... postgres: checkpointer postgres 107175 107172 ... postgres: background writer postgres 107176 107172 ... postgres: walwriter postgres 107177 107172 ... postgres: autovacuum launcher postgres 107178 107172 ... postgres: archiver postgres 107179 107172 ... postgres: stats collector postgres 107180 107172 ... postgres: autoprewarm master postgres 107181 107172 ... postgres: logical replication launcher postgres 107186 107172 ... postgres: postgres postgres [local] idle