PostgreSQL缓存
目录[-]
缓存.... !!, 它很难在一篇文章中解释清楚。但是我会努力分享我从Heikki, Robert Haas, Bruce Momjian那里学到的知识。在PostgreSQL里有两层:PG共享缓冲和操作系统页面缓存,任何读写都会通过操作系统缓存(迄今为止还没有其它途径)。Postgres把数据写在操作系统页面缓存,用户觉得数据好像回写到了磁盘,之后操作系统缓存才会写到对应的物理磁盘位置。PG共享缓冲无法控制系统页面缓存,甚至连系统缓存是什么都不知道。所以,Postgres DBA或者专家给出的大多数建议都是更快的磁盘读写或者更好的缓存。
PostgreSQL的缓存/缓冲和其它数据库十分相像并且十分复杂。因为我有Oracle和mindset背景,所以我使用怎么样/什么时候/什么/为什么等提问方式,关于数据库的缓冲缓存,固定的缓冲,刷新数据库缓存,以及预加载数据库等方面,我都是从这种方式获得答案的,然而这种方式有点与众不同。尽管我的问题很烦人,但是他们总是耐心的回答,使我明白扩展我的知识,反过来,你才能阅读这篇博文... :) ..
在一些学习上,我画了一幅Postgres中数据在内存和磁盘之间传递的,以及一些重要的工具和Robert Hass提供的新补丁(pg_prewarm).
pg_buffercache
它是一个contrib模块,它会告诉你什么是PostgreSQL缓存。像下面安装:
1
|
postgres=# CREATE EXTENSION pg_buffercache |
pgfincore
它有一个显示数据在操作系统页面缓存中信息的功能。Pgfincore和pg_buffercache联合会十分方便的。现在,它可以同时获得PG缓冲和操作系统页面缓存信息。感谢Cerdic Villemain。Pgfincore的主干是fadvise,fincore,它俩是linux ftools。你可以使用源码安装fincore/fadvise。你可以使用pgfincore contrib模块或者ftools,都会产生同样的结果。我试了两者,它们都十分简单优秀。
安装:
下载最新版本:
http://pgfoundry.org/frs/download.php/3186/pgfincore-v1.1.1.tar.gz
使用root用户:
1
2
3
4
5
6
|
export PATH= /usr/local/pgsql91/bin :$PATH // 设置执行pg_config的路径 tar -xvf pgfincore-v1.1.1. tar .gz cd pgfincore-1.1.1 make clean make make install |
现在连接到PG,运行下面的命令:
1
|
postgres=# CREATE EXTENSION pgfincore; |
pg_prewarm
预加载关系/索引到PG缓存中,在PostgreSQL中可能吗?当然可以了,感谢Robert Hass,他提交一些补丁到社区,期待它能够在PG 9.2或者PG 9.3中可行。然而,你可以使用这个补丁在PG 9.1做一些测试。
pg_prewarm
有三种模式:
- PREFETCH: 异步获取数据块到操作系统缓存中,而不是PG缓冲(提示只是操作系统缓存)
- READ:读取所有的数据块到虚拟缓存中,然后写到操作系统缓存中(提示只是操作系统缓存)
- BUFFER:读取所有的或者一些数据块到数据库缓冲中。
安装:
我把pg_prewarm补丁加入到PG源码安装中,你需要调整你的每步安装。
- 解压PG源码路径: /usr/local/src/postgresql-9.1.3
- PG安装路径: /usr/local/pgsql91
- 所有下载路径: /usr/local/src
注意:应用pg_prewarm补丁之前安装PG
1. 下载补丁,放在/usr/local/src
http://archives.postgresql.org/pgsql-hackers/2012-03/binRVNreQMnK4.bin
补丁附加邮件地址
2. 在下载之后,到PG源码目录,然后执行下面几步。
1
2
3
4
|
# cd /usr/local/src/postgresql-9.1.3 # patch -p1 < ../pg_prewarm.bin (在下载之后我重命名了pg_prewarm) # make -C contrib/pg_prewarm # make -C contrib/pg_prewarm instal |
3. 上面的命令会在$PGPATH/contrib/extension目录里创建文件。现在准备添加contrib模块了。
1
2
3
4
5
6
7
8
9
10
11
|
postgres=# create EXTENSION pg_prewarm; CREATE EXTENSION postgres=# \dx List of installed extensions Name | Version | Schema | Description ----------------+---------+------------+---------------------------------------- pg_buffercache | 1.0 | public | examine the shared buffer cache pg_prewarm | 1.0 | public | prewarm relation data pgfincore | 1.1.1 | public | examine and manage the os buffer cache plpgsql | 1.0 | pg_catalog | PL/pgSQL procedural language (4 rows ) |
文档:
1
2
3
|
<span>/usr/ local /src/postgres-9.1.3/doc/src/sqml [root@localhost sgml]# ll pgpre* -rw-r --r-- 1 root root 2481 Apr 10 10:15 pgprewarm.sgml</span> |
dstat
它是vmstat, netstat, top等工具的组合到一起成了一个"dstat"linux命令。当数据库表现不正常时,从操作系统级别了解语句,我们会打开好几个终端来显示进程,内存,磁盘读写,网络信息,但是在这些窗口切换是十分痛苦的。所以,dstat有几个选项来帮助显示所有的命令在一个输出窗口中。
安装:
Dstat下载连接:(RHEL 6)
wget http://pkgs.repoforge.org/dstat/dstat-0.7.2-1.el6.rfx.noarch.rpm
或者
yum install dstat
文档:http://dag.wieers.com/home-made/dstat/
Linux ftools
在被设计在现代的linux操作系统中用来调用像mincore, fallocate, fadivse等的工具。Ftools它会帮助你找出那些文件在操作系统缓存中。使用perl/python脚本,你可以获得操作系统页面缓存信息在pg_class.relfilenode对象中。pg_fincore就是建立在它之上的。你可以使用pgfincore或者ftools脚本。
安装:
从这个连接下载.tar.gz
https://github.com/david415/python-ftools cd python-ftools
python setup.py build
export PYTHONPATH=build/lib.linux-x86_64-2.5
python setup.py install 注意:你应该在安装python-ftools之前就已经安装好了。
现在,我使用例子来检验这些工具。在这个例子中,有一个表,它有一个索引和序列(sequence),大小为100多MB。
postgres=# \d+ cache
Table "public.cache"
Column | Type | Modifiers | Storage | Description
--------+---------+-----------------------------------------+----------+-------------
name | text | | extended |
code | integer | | plain |
id | integer | default nextval('icache_seq'::regclass) | plain |
Indexes:
"icache" btree (code)
Has OIDs: no
使用查询来了解这表,序列和它的索引所占的大小.
postgres=# SELECT c.relname AS object_name,
CASE when c.relkind='r' then 'table'
when c.relkind='i' then 'index'
when c.relkind='S' then 'sequence'
else 'others'
END AS type,pg_relation_size(c.relname::text) AS size, pg_size_pretty(pg_relation_size(c.relname::text)) AS pretty_size
FROM pg_class c
JOIN pg_roles r ON r.oid = c.relowner
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
WHERE (c.relkind = ANY (ARRAY['r'::"char", 'i'::"char", 'S'::"char",''::"char"])) AND n.nspname = 'public'; object_name | type | size | pretty_size
-------------+----------+----------+-------------
icache_seq | sequence | 8192 | 8192 bytes
cache | table | 83492864 | 80 MB
icache | index | 35962880 | 34 MB
(3 rows) Total object size 'cache' postgres=# select pg_size_pretty(pg_total_relation_size('cache'));
pg_size_pretty
----------------
114 MB
(1 row)
我已经写了联合pgfincore和pg_buffercache的一个简单查询来获得PG缓冲和操作系统页面缓存的信息。我会在这个查询贯穿整个例子,仅仅复制这个查询就好了。
select rpad(c.relname,30,' ') as Object_Name,
case when c.relkind='r' then 'Table' when c.relkind='i' then 'Index' else 'Other' end as Object_Type,
rpad(count(*)::text,5,' ') as "PG_Buffer_Cache_usage(8KB)",
split_part(pgfincore(c.relname::text)::text,','::text,5) as "OS_Cache_usage(4KB)"
from pg_class c inner join pg_buffercache b on b.relfilenode=c.relfilenode
inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database() and c.relnamespace=(select oid from pg_namespace where nspname='public'))
group by c.relname,c.relkind
order by "PG_Buffer_Cache_usage(8KB)"
desc limit 10; object_name | object_type | PG_Buffer_Cache_usage(8KB) | OS_Cache_usage(4KB)
-------------+-------------+----------------------------+---------------------
(0 rows) 注意: 我已经刷新PG缓冲和操作系统页面缓存。所以,缓存/缓冲没有任何数据.
使用pg_prewarm预加载关系/索引:
在之前,我刷新整个"Cache"表的顺序遍历查询和之前预加载关系/索引的时间。
postgres=# explain analyze select * from cache ;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Seq Scan on cache (cost=0.00..26192.00 rows=1600000 width=19) (actual time=0.033..354.691 rows=1600000 loops=1)
Total runtime: 427.769 ms
(2 rows)
现在让我们使用pg_prewarm来预加载关系/索引/序列,然后查看查询计划。
postgres=# select pg_prewarm('cache','main','buffer',null,null);
pg_prewarm
------------
10192
(1 row)
postgres=# select pg_prewarm('icache','main','buffer',null,null);
pg_prewarm
------------
4390
(1 row) Output of combined buffers:
object_name | object_type | PG_Buffer_Cache_usage(8KB) | OS_Cache_usage(4KB)
-------------+-------------+----------------------------+---------------------
icache | Index | 4390 | 8780
cache | Table | 10192 | 20384
(2 rows)
pgfincore 输出:
postgres=# select relname,split_part(pgfincore(c.relname::text)::text,','::text,5) as "In_OS_Cache" from pg_class c where relname ilike '%cache%';
relname | In_OS_Cache
------------+-------------
icache_seq | 2
cache | 20384
icache | 8780
(3 rows) or for each object. postgres=# select * from pgfincore('cache');
relpath | segment | os_page_size | rel_os_pages | pages_mem | group_mem | os_pages_free | databit
------------------+---------+--------------+--------------+-----------+-----------+---------------+---------
base/12780/16790 | 0 | 4096 | 20384 | 20384 | 1 | 316451 |
(1 row)
To retrieve similar information using python-ftools script you need to know objects relfilenode number, check below.
使用python-ftools脚本也会获得相似的信息,你应该知道relfilenode对象的编号。像下面一样查看。
postgres=# select relfilenode,relname from pg_class where relname ilike '%cache%';
relfilenode | relname
-------------+----------------
16787 | icache_seq /// 你执行的序列
16790 | cache /// 表
16796 | icache /// 索引
(3 rows)
使用python-ftools脚本
有趣吧....!!!!.
现在比较一下预加载表到缓冲之后的explain plan
postgres=# explain analyze select * from cache ;
QUERY PLAN
------------------------------------------------------------------------------------------------------------------
Seq Scan on cache (cost=0.00..26192.00 rows=1600000 width=19) (actual time=0.016..141.804 rows=1600000 loops=1)
Total runtime: 215.100 ms
(2 rows)
怎样刷新在操作系统缓存中的关系/索引 ?
使用pgfadvise,你可以预加载或者刷新关系到操作系统缓存。获得更多信息,在终端中使用\df pgfadvise*来显示所有与pgfadvise相关的函数。下面是刷新操作系统缓存的一个例子。
postgres=# select * from pgfadvise_dontneed('cache');
relpath | os_page_size | rel_os_pages | os_pages_free
------------------+--------------+--------------+---------------
base/12780/16790 | 4096 | 20384 | 178145
(1 row)
postgres=# select * from pgfadvise_dontneed('icache');
relpath | os_page_size | rel_os_pages | os_pages_free
------------------+--------------+--------------+---------------
base/12780/16796 | 4096 | 8780 | 187166
(1 row)
postgres=# select relname,split_part(pgfincore(c.relname::text)::text,','::text,5) as "In_OS_Cache" from pg_class c where relname ilike '%cache%';
relname | In_OS_Cache
------------+-------------
icache_seq | 0
cache | 0
icache | 0
(3 rows)
通过使用dstat,这些信息显示在一个窗口中,如你可以查看读写比例。更多信息使用 dstat --list
dstat -s --top-io --top-bio --top-mem
使用pg_prewarm的range功能预加载随机块.
假设,因为一些原因,你想刷新服务器,但是有一个很大的表它在缓存中,而且执行的很好。在刷新中,缓存 中就没有了你的表了,要回到刷新前的状态,你不得不知道多少表块在缓存中以及使用pg_prewarm的range选项来预加载它。
我通过pg_buffercache来查询已创建的表,然后我使用pg_prewarm的range选项来发送块。通过这样,共享缓存就像先前加载到缓存中一样回来了。请看例子
select c.relname,count(*) as buffers from pg_class c
inner join pg_buffercache b on b.relfilenode=c.relfilenode and c.relname ilike '%cache%'
inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database())
group by c.relname
order by buffers desc;
relname | buffers
---------+---------
cache | 10192
icache | 4390
(2 rows)
Note: These are the blocks in buffer. postgres=# create table blocks_in_buff (relation, fork, block) as select c.oid::regclass::text, case b.relforknumber when 0 then 'main' when 1 then 'fsm' when 2 then 'vm' end, b.relblocknumber from pg_buffercache b, pg_class c, pg_database d where b.relfilenode = c.relfilenode and b.reldatabase = d.oid and d.datname = current_database() and b.relforknumber in (0, 1, 2);
SELECT 14716
刷新服务器以及从"blocks_in_buff"表中查看预加载和表相关的随机块的缓存。
postgres=# select sum(pg_prewarm(relation, fork, 'buffer', block, block)) from blocks_in_buff;
sum
-------
14716
(1 row) postgres=# select c.relname,count(*) as buffers from pg_class c
inner join pg_buffercache b on b.relfilenode=c.relfilenode and c.relname ilike '%cache%'
inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database())
group by c.relname
order by buffers desc;
relname | buffers
---------+---------
cache | 10192
icache | 4390
(2 rows)
看,我的共享缓存又回来工作了。
欢呼吧... ! 精彩继续。
PostgreSQL缓存的更多相关文章
- PostgreSQL 缓存
PostgreSQL physical storage和 inter db 值得阅读 数据在物理介质上存储是以page的形式,大小为8K,如下: a tuple或an item是行的同义词 a ...
- 【转】2016/2017 Web 开发者路线图
链接:知乎 [点击查看大图] 原图来自LearnCodeAcademy最火的视频,learncode是YouTube上最火的Web开发教学频道,介绍包括HTML/CSS/JavaScript/Subl ...
- 如何使用Docker部署PHP开发环境
本文主要介绍了如何使用Docker构建PHP的开发环境,文中作者也探讨了构建基于Docker的开发环境应该使用单容器还是多容器,各有什么利弊.推荐PHP开发者阅读.希望对大家有所帮助. 环境部署一直是 ...
- Django---进阶12
目录 Auth模块 方法总结 如何扩展auth_user表 项目开发流程 表设计 作业 Auth模块 """ 其实我们在创建好一个django项目之后直接执行数据库迁移命 ...
- day71 django收尾
目录 一.Auth模块 1 简介 2 方法总结 3 如何扩展auth_user表 二.bbs表介绍 1 项目开发流程 2 bbs七张表关系 一.Auth模块 1 简介 在我们创建好一个django项目 ...
- Django学习day13随堂笔记
每日测验 """ 今日考题 1.什么是django中间件,它的作用是什么,如何自定义中间件,里面有哪些用户可以自定义的方法,这些方法有何特点 2.基于django中间件的 ...
- Tapdata 肖贝贝:实时数据引擎系列(六)-从 PostgreSQL 实时数据集成看增量数据缓存层的必要性
摘要:对于 PostgreSQL 的实时数据采集, 业界经常遇到了包括:对源库性能/存储影响较大, 采集性能受限, 时间回退重新同步不支持, 数据类型较复杂等等问题.Tapdata 在解决 Pos ...
- CentOS7下安装并简单设置PostgreSQL笔记
为什么是PostgreSQL? 在.NET Core诞生之前,微软平台上最常见的开发组件便是.NET Framework + SQL Server了,但是现在.NET Core终于让跨平台部署成为了现 ...
- 影响postgresql性能的几个重要参数
转载 一篇蛮老的文章了,但是还是很有用,可参考修补. PG的配置文件是数据库目录下的postgresql.conf文件,8.0以后的版本可支持K,M,G这样的参数,只要修改相应参数后重新启动PG服务就 ...
随机推荐
- android apk 自我保护技术-完整性校验
关于防止android apk被反编译的技术我们前面已经讲了四种. 加壳技术 运行时修改字节码 伪加密 对抗JD-GUI 如果有不明白的可以查看我的博客的前四篇中关于这四种技术的介绍.接下来我们接着介 ...
- 转:在Linux上安装ant环境
1.从http://ant.apache.org 上下载tar.gz版ant 2.复制到/usr下 3.tar -vxzf apahce-ant-1.9.2-bin.tar.gz 解压 4.chow ...
- 打包python文件为exe文件(PyInstaller工具使用方法)
最近做的新浪微博爬虫程序,打算打包成.exe软件以方便使用,网上找到一个很好的打包工具pyinstaller,这里记录一下打包的方法. 一.下载pyinstaller 我使用的版本为PyInstall ...
- 【网络爬虫】【python】网络爬虫(五):scrapy爬虫初探——爬取网页及选择器
在上一篇文章的末尾,我们创建了一个scrapy框架的爬虫项目test,现在来运行下一个简单的爬虫,看看scrapy爬取的过程是怎样的. 一.爬虫类编写(spider.py) from scrapy.s ...
- 27.集成EFCore配置Client和API
copy链接字符串,这是一个官方的字符串,直接复制过来,放在上面. 添加包的引用 引入IdentityServer4.EntityFramework的命名空间 主要是这个地方初始化我们的数据库 Ope ...
- HDU - 5534 Partial Tree(每种都装的完全背包)
Partial Tree In mathematics, and more specifically in graph theory, a tree is an undirected graph in ...
- win10怎样彻底关闭windows Defender
首先,我们在电脑中需要进入注册表编辑器进行修改,win10电脑进入windows Defender可以有两种方式,第一种是通过电脑自带的小娜进入,第二种则是常规的win加r. 不管使用哪种方式,首 ...
- linux下 C编程改变输出字体颜色
格式: echo "\033[字背景颜色;字体颜色m字符串\033[0m"例如:echo "\033[41;36m something here \033[0m" ...
- OVN学习(二)
部署OVN实验环境 同OVN学习(一) L3网络 创建逻辑交换机和路由 ### Central节点 ### 创建逻辑交换机和路由器 # ovn-nbctl ls-add inside # ovn-nb ...
- Linux shell 单引号和双引号
在编写shell脚本的时候经常会用到引号,有些时候却老是忘记单引号和双引号之间的区别, 所以就整理一下供以后脑子不好使了的时候前来复习一下.首先说下他们的共同点: 好像就只有 一个,就是它们都可以用来 ...