pg_prewarm模块提供一种方便的方法把关系数据载入到操作系统缓冲区或者 PostgreSQL缓冲区。可以使用pg_prewarm函数手工执行预热,或者通过在shared_preload_libraries中包括pg_prewarm来自动执行预热。在后一种情况中,系统将运行一个后台工作者,它会周期性地把共享内存中的内容记录在一个名为autoprewarm.blocks的文件中,并且在重新启动后用两个后台工作者重新载入那些块。

函数
pg_prewarm(regclass, mode text default 'buffer', fork text default 'main',
first_block int8 default null,last_block int8 default null) RETURNS int8
第一个参数是要预热的关系。第二个参数是要使用的预热方法,下文将会 进一步讨论。第三个参数是要被预热的关系分叉,通常是main。第四个参数是要预热的第一个块号(NULL也被接受,它等同于 零)。第五个参数是要预热的最后一个块号(NULL表示一直 预热到关系的最后一个块)。返回值是被预热的块数。
有三种可用的预热方法。prefetch会向操作系统发出异步预取请求(如果支持异步预取),不支持异步预取则抛出一个错误。read会读取要求范围的块。与prefetch 不同,它是同步的并且在所有平台上都被支持,但是可能较慢。buffer会把要求范围的块读入道数据库的缓冲区。
注意使用任意一种方法尝试预热比能缓存的数量更多的块 — 使用 prefetch或者read(由OS)或者使用 buffer(由PostgreSQL ) — 将很可能导致高编号块被读入时把低编号的块从缓冲区中逐出的情况。被预热的数据也不享受对缓冲区替换的特别保护,因此其他系统活动可能会在刚刚被预热的块被读入后很快就将它们逐出。反过来,预热也可能把其他数据逐出缓存。由于这些原因,预热通常在启动时最有用,那时缓冲大部分都为空。
autoprewarm_start_worker() RETURNS void
启动主要的autoprewarm工作者。这通常将会自动发生,但是如果没有在服务器启动时配置自动预热并且用户希望在稍晚的时候启动该工作者,这个函数就能发挥作用。
autoprewarm_dump_now() RETURNS int8
立即更新autoprewarm.blocks。如果autoprewarm工作者没有运行但用户希望它在下一次重启后运行,则这个函数会很有用。返回值是写入到autoprewarm.blocks中的记录数。
配置参数
pg_prewarm.autoprewarm (boolean)
控制服务器是否应该运行autoprewarm工作者。默认这个参数为on。这个参数只能在服务器启动时设置。
pg_prewarm.autoprewarm_interval (int)
这是更新autoprewarm.blocks的间隔。默认是300秒。如果被设置为0,该文件将不会以常规的间隔方式转储,而是只在服务器关闭时转储。
测试:
创建一个500W数据的测试表t2。


查看执行select * from t2这个sql语句的执行计划,可以看到第一次执行22124个数据库全部是从磁盘读取,第二次读取有32个数据块进行了缓存,对于较大的表尤其是大于四分之一shared_buffers大小的表,就算读取过一次,也只是缓存一小部分数据而已。

重启数据库,并对t2表进行预热,然后再次查看执行计划,可以看到有1600多个数据块进行缓存并没有全部缓存,主要原因是我的测试环境是虚拟机,配置数据库内存为128M,条表大小为173M。

pg_prewarm作为数据库自带的插件,它的源码路径在contrib/pg_prewarm目录下。
在上次更新的公众号中已经提到了扩展,那么我们下面顺便看一下pg_prewarm,
可以看到pg_prewarm目录下有创建一个扩展所必须的所有文件其中包括但不限于sql、c、Makefile、control等文件。

以下是makefile文件内容。

以下是control文件内容。

在pg_prewarm.c文件中可以看到只有一个函数pg_prewarm,在源码中定义了一个枚举,表示三种可用的预热方法。prefetch会向操作系统发出异步预取请求(如果支持异步预取),不支持异步预取则抛出一个错误。read会读取要求范围的块。与prefetch 不同,它是同步的并且在所有平台上都被支持,但是可能较慢。buffer会把要求范围的块读入道数据库的缓冲区。

数据库中执行如下:

代码开始对参数合法性进行了一系列判断,包括是否为空,是否是有效值、是否小于等。


所有准备工作完成然后根据不同的预热方法开始预热数据。

作者:Robert Haas <rhaas@postgresql.org>




