pg预热插件pg_prewarm_Hehuyi_In的博客-程序员ITS301_pg_prewarm

技术标签: PostgreSQL  性能  

PostgreSQL内核中引入了一个很有意思的插件,pg_prewarm。可以用于在系统重启时,手动加载经常访问的表到操作系统的cache或PG的shared buffer,从而减少检查系统重启对应用的影响。这个插件通过以下patch加入PG内核 https://git.postgresql.org/gitweb/?p=postgresql.git;a=commitdiff;h=c32afe53c2e87a56e2ff930798a5588db0f7a516

pg_prewarm的开发者在设计pg_prewarm时,把它设计成一个执行单一任务的工具,尽求简单,所以我们看到的pg_prearm功能和实现都非常简单。下面我们对它进行性能实测并分析一下它的实现。

一、 基本信息

利用下面的语句可以创建此插件:

create EXTENSION pg_prewarm;

实际上,创建插件的过程只是用下面的语句创建了pg_prewarm函数。这个函数是此插件提供的唯一函数:

CREATE FUNCTION pg_prewarm(regclass,
mode text default buffer,
fork text default main,
first_block int8 default null,
last_block int8 default null)
RETURNS int8
AS MODULE_PATHNAME, pg_prewarm
LANGUAGE C

参数含义如下

  • regclass:要做prewarm的表名
  • mode:prewarm模式。prefetch表示异步预取到os cache;read表示同步预取;buffer表示同步读入PG的shared buffer
  • fork:relation fork的类型。一般用main,其他类型有visibilitymap和fsm
  • first_block & last_block:开始和结束块号。表的first_block=0,last_block可通过pg_class的relpages字段获得
  • RETURNS int8:函数返回pg_prewarm处理的block数目(整型)

 

二、 性能实测

再来看看prewarm性能上能达到多大效果。将PG的shared buffer设为2G,OS内存7G。然后创建个大小近1G的表test:

pgbench=#  SELECT pg_size_pretty(pg_total_relation_size(test));
pg_size_pretty
----------------
995 MB

在每次都清掉操作系统cache和PG的shared buffer的情况下,分别测试下面几种场景:

1)不进行pg_prewarm

pgbench=# explain analyze select count(*) from test;
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------
Aggregate  (cost=377389.91..377389.92 rows=1 width=0) (actual time=22270.304..22270.304 rows=1 loops=1)
->  Seq Scan on test  (cost=0.00..327389.73 rows=20000073 width=0) (actual time=0.699..18287.199 rows=20000002 loops=1)
Planning time: 0.134 ms
Execution time: 22270.383 ms

可以看到,近1G的表,全表扫描一遍,耗时22秒多。

2)read模式prewarm(test表的数据被同步读入os cache)

pgbench=# select pg_prewarm(test, read, main);
pg_prewarm
------------
127389

pgbench=# explain analyze select count(*) from test;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
Aggregate  (cost=377389.90..377389.91 rows=1 width=0) (actual time=8577.767..8577.767 rows=1 loops=1)
->  Seq Scan on test  (cost=0.00..327389.72 rows=20000072 width=0) (actual time=0.086..4716.444 rows=20000002 loops=1)
Planning time: 0.049 ms
Execution time: 8577.831 ms

时间降至8秒多!这时反复执行全表扫描,时间稳定在8秒多(但cost没有降低)。

3)buffer模式prewarm(同步读入PG的shared buffer)

pgbench=# select pg_prewarm(test, buffer, main);
pg_prewarm
------------
127389

pgbench=# explain analyze select count(*) from test;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
Aggregate  (cost=377389.90..377389.91 rows=1 width=0) (actual time=8214.277..8214.277 rows=1 loops=1)
->  Seq Scan on test  (cost=0.00..327389.72 rows=20000072 width=0) (actual time=0.015..4250.300 rows=20000002 loops=1)
Planning time: 0.049 ms
Execution time: 8214.340 ms

比read模式时间略少,但相差不大。可见如果os cache够大,数据取到OS cache还是shared buffer对执行时间影响不大(在不考虑其他应用影响PG的情况下)。

4)prefetch模式

这里我们有意在pg_prewarm返回后,立即执行全表查询。这样在执行全表查询时,可能之前的预取还没完成,从而使全表查询和预取并发进行,缩短了总的响应时间。

explain analyze select pg_prewarm(test, prefetch, main);
QUERY PLAN
------------------------------------------------------------------------------------------
Result  (cost=0.00..0.01 rows=1 width=0) (actual time=1011.338..1011.339 rows=1 loops=1)
Planning time: 0.124 ms
Execution time: 1011.402 ms

explain analyze select count(*) from test;
QUERY PLAN
--------------------------------------------------------------------------------------------------------------------------
Aggregate  (cost=377389.90..377389.91 rows=1 width=0) (actual time=8420.652..8420.652 rows=1 loops=1)
->  Seq Scan on test  (cost=0.00..327389.72 rows=20000072 width=0) (actual time=0.065..4583.200 rows=20000002 loops=1)
Planning time: 0.344 ms
Execution time: 8420.723 ms

可以看到,总的完成时间也是8秒多,使用pg_prewarm做预取大大缩短了总时间。因此在进行全表扫描前,做一次异步的prewarm,不失为一种优化全表查询的方法。

 

三、 实现

pg_prewarm的代码只有一个pg_prewarm.c文件。

1. prefetch模式

对于表的每个block,调用一次PrefetchBuffer,后面的调用为:

PrefetchBuffer -> smgrprefetch  -> mdprefetch -> FilePrefetch -> posix_fadvise(POSIX_FADV_WILLNEED)

可见,它是最终调用posix_fadvise,把读请求交给操作系统,然后返回,实现的异步读取。

2. read和buffer模式

最终都调用了read,来实现同步读入OS cache和shared buffer。buffer模式实际是先读入OS cache,再拷贝到shared buffer

read模式:smgrread -> mdread -> FileRead  -> read

buffer模式:ReadBufferExtended -> ReadBuffer_common -> smgrread -> mdread -> FileRead -> read


四、 问题

可能有人比较疑惑:执行1次select * from 不就可以将表的数据读入shared buffer和OS cache而实现预热了吗?不是比做这样一个插件更简单?实际上,对于较大的表(超过shared buffer 1/4),进行全表扫描时,PG认为没必要为这种操作使用所有shared buffer,只会让其使用很少的一部分buffer,一般只有几百K,详细描述可以参见关于BAS_BULKREAD策略的代码和README)。所以,预热大表是不能用一个查询直接实现的,而pg_prewarm正是在这方面大大方便了用户。

 

参考:

http://mysql.taobao.org/monthly/2015/02/04/

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/Hehuyi_In/article/details/102653909

智能推荐

oracle 01405 提取的值为null,OCI : ORA-01405: 提取的列值为 NULL_陈思er的博客-程序员ITS301

#include // OCI开发环境配置// 远端oracle服务器端装好,配好TNS服务名称//// 安装oracle客户端软件时,选第3项(开发工具).// oracle客户端安装完后,用自带的网络助手配置监听器和远端的TNS服务名称//// 将工程设定为win64, 包含进OCI头文件和库文件.// 在打开远端oracle服务器(进入服务器桌面)的情况下,就可以运行调试测试程序了.// 不...

ip地址0.0.0.0与127.0.0.1的区别(转载)_anlie6424的博客-程序员ITS301

原文链接:http://blog.csdn.net/ttx_laughing/article/details/58586907最近在项目开发中发现一个奇怪的问题,当服务器与客户端在同一台机器上时,用服务器ip(本地主机ip)192.168.1.xxx、127.0.0.1以及0.0.0.0都能登陆服务器,于是找点资料研究一下。其实,最开始是发现服务器ip填0能登陆成功,后来知道了系统...

qt绘制文本_sunxiaopengsun的博客-程序员ITS301_qt 绘制文本

转载地址:点击打开链接简述前面讲解了 Qt 图形的基本绘制,包括: 直线、弧线、矩形、椭圆、图片、多边形,以及其它一些高级用法,比如:渐变、转换等。本节主要分享文本的绘制。主要通过 QPainter 的 darwText() 函数来实现,里面包含多个重载函数,其中,可以通过 QRect 来指定绘制的区域,也可以通过 QPoint 来指定绘制的起始点。QFon

七年级 电子计算机 教材分析,七年级计算机教学计划_weixin_39955938的博客-程序员ITS301

根据计划内容的明确性指标,可以将计划分具体性计划和指导性计划。以下是小编收集的计算机教学计划相关内容,欢迎查看!一、指导思想当今人类社会已经进入21世纪,以计算机、网络和通信技术为核心的现代信息技术在社会各个领域都得到了广泛的应用,并逐渐改变着人们的学习、工作和生活方式。信息的获取、传输、处理和应用能力已经成为现代新人类最基本的能力与文化水平的标志。在这种大环境下,本学期的信息技术教学工作,将严格...

Java-lambda表达式入门看这一篇就够了_吾仄lo咚锵的博客-程序员ITS301

Lambda表达式,也可称为闭包,是JDK8的新特性。Lambda 允许把函数作为一个方法的参数(函数作为参数传递进方法中),可以使代码变的更加简洁紧凑。Lambda表达式是一个可传递的代码块,可以在以后执行一次或多次。文章目录概述语法函数式接口方法引用构造器引用变量作用域处理lambda表达式

如何调出手机信任计算机的指令,苹果手机怎么连接到电脑上面去发(苹果在哪设置信任电脑)..._艺空的博客-程序员ITS301

iphone怎么连接到电脑?现在iphone的普及率还算是比较高的,但是现在让很多网友郁闷的是不知道自己的iphone怎么链接到电脑上去。iPhone和其他Android智能手机不一样,连接电脑以后,如果不安装PC端的管理软件,并不能对其进行任何的操作。iPhone6连接电脑的方法有很多,可以在电脑上安装iTunes最新版,大家百度一下iTunes的安装使用方法即可。但根据多数用户的体验,用iTu...

随便推点

linux 游戏 发行版,向游戏玩家推荐的六款最佳 Linux 发行版_lissssssll的博客-程序员ITS301

原标题:向游戏玩家推荐的六款最佳 Linux 发行版Linux过去是完全基于命令行的操作系统,后来它有了基本的图形用户界面(GUI)。而如今我们有了高级的桌面环境,比如KDE Plasma等。现在,游戏是Linux上的另一个亮点。我们有一些出色的Linux游戏。1SteamOS好了,要介绍的第一款就是SteamOS。SteamOS是一款基于Debian的Linux发行版,随带Valve的Steam...

EdgeX Foundry -- Geneva版本 -- Consul_it's all pointless的博客-程序员ITS301

day1: docker-edgex-consul-1.2.0注册配置服务边缘智能网关中具有多个微服务,微服务之间通过RESTAPI相互访问,服务调用者需要知道被调用服务的地址信息,才能进行访问。由于服务的访问信息可以动态改变,人为地添加系统中所有服务的访问信息不仅效率低,而且可靠性和稳定性无法保障。因此需要一套完善的服务发现机制来实现服务注册、服务发现自动化,并且可以动态地实现服务的注册、查找和删除。配置和注册服务是基于开源的Consul服务发现框架设计的。配置和注册服务是整个系统中所有.

数据采集实战:如何自动化运营微博?_hanli0902的博客-程序员ITS301

自动化测试工具Selenium 更关注程序执行的流程本身,比如找到指定的元素,设置相应的值,然后点击操作。 Puppeteer 是浏览者的视角,比如光标移动到某个元素上,键盘输入某个内容等。如果想定位一个元素,可以通过 id、name、class、tag、链接上的全部文本、链接上的部分文本、XPath 或者 CSS 进行定位,在 Selenium Webdriver 中提供了这 8 种方法方便定位元素。通过 id 定位:使用 find_element_by_id() 函数。比如定位 id=log

机器学习算法—朴素贝叶斯(分类方法)超详细!!!_cav_kd的博客-程序员ITS301

机器学习算法—朴素贝叶斯(分类方法)超详细!!!相关概率论知识:注:以下公式希望大家可以自己推导一下,有助于更好的理解我们的朴素贝叶斯算法,这一次的讲解,只是为了入门的宝贝可以更好的理解和 开始学会运用算法,后面的更新,将会是对于朴素贝叶斯算法的优化,基于这个例子的优化1、相互独立事件:假设A、B相互独立,那么有:**乘法公式:**P(AB)=P(A)*P(B)2、表示事件B已经发生的前提下,事件A发生的概率,叫做事件B发生下事件A的条件概率。贝叶斯准则告诉我们,如果已知P(A|B),要求P(B|

vue结合vue-print-nb实现打印功能_迷路时你就往前走i的博客-程序员ITS301_vue-pringt-nb打印空白页

安装vue-print-nbnpm i vue-print-nb --save在main.js文件中导入import Print from 'vue-print-nb'Vue.use(Print);使用使用id<template> <div> <button v-print="'#printcontent'">打印</button> <div>888</div> <div id="printco

pppoe的工作过程_Lostyears的博客-程序员ITS301

PPPoE(PPP over Ethernet)是在以太网上建立PPP连接,由于以太网技术十分成熟且使用广泛,而PPP协议在传统的拨号上网应用中显示出良好的可扩展性和优质的管理控制机制,二者结合而成的PPPoE协议得到了宽带接入运营商的认可并广为采用。PPPoE不仅有以太网的快速简便的特点,同时还有PPP的强大功能,任何能被PPP封装的协议都可以通过PPPoE传输。 PPPoE建立