在使用PostgreSQL要设置shared_buffers的大小的时候,我们通常的建议值是操作系统内存的25%,过大或者过小的值都会影响数据库的性能。此时我们有时候会产生一个疑问,为什么类似的参数,ORACLE和MYSQL都分配了操作系统大部分内存,例如ORACLE的sga通常设置为物理内存的80%,或者MySQL的innodb_buffer_pool_size 通常也设置为80%,而PostgreSQL的shared_buffers确设置的比例这么小呢。
其实是因为Postgresql采用数据库实例buffer(shared_buffers)和操作系统buffer双缓存(effective_cache_size)的工作模式,PostgreSQL数据库必须高度依赖操作系统缓存,它依赖于操作系统来了解文件系统、磁盘布局以及如何读写数据文件。缓存作为数据库的一个核心组件,shared_buffers决定了数据库实例层面的可用内存,而系统中预计有多少缓存是effective_cache_size决定的。而且effective_cache_size不仅是缓存经常访问的数据,它同时帮助优化器确定实际存在多少缓存,指导优化器生成最佳执行计划。
而ORACLE和MYSQL把大部分系统内存给到了数据库缓存,倾向于不使用OS cache,支持使用 direct IO——在应用层Buffer和磁盘之间直接建立通道,绕过操作系统缓存。这样在读写数据的时候就能够减少上下文切换次数,同时也能够减少数据拷贝次数,从而提高效率。而原生PostgreSQL是不支持direct IO的,这一点和ORACLE、MySQL还是有着比较本质上的差异的。(事情也不绝对,例如Aurora PostgreSQL消除了双缓存,并且不使用文件系统缓存)
当我们日常在数据库里写入数据后,bgwriter进程将脏缓冲区刷新到磁盘时,页面实际上是先刷新到OS缓存,然后再刷新到磁盘。
而执行查询,会先从shared_buffers里查找,一旦在shared_buffers里命中了数据页,就永远不会再到操作系统缓存里进行查找。但如果在shared_buffers里没命中,则会继续从OS cache里找寻,如果在OS cache里命中了,则把数据加载到shared_buffers里去。
如果在shared_buffers和OS cache里都没有命中的话,则会把数据先加载到操作系统缓存(OS cache ),然后再加载到shared buffers。
这种双缓存的工作模式意味着OS cache和shared_buffers可以保存相同的页面。有一定可能可能会导致空间浪费,但OS缓存使用的是LRU算法,而不是shared_buffers的时钟扫描算法(clock sweep algorithm.)。一旦在shared_buffers里命中了数据页,就永远不会到操作系统缓存里进行查找,因此,在shared_buffers里长期使用到的部分,在OS cache里实际上会很容易就被清理掉了。
可以使用pg_buffercache和pgfincore这两个插件去查看缓存里的数据量。
pgfincore工具github的地址如下https://github.com/klando/pgfincore
git clone git://git.postgresql.org/git/pgfincore.git
make install
[xmaster@mogdb-kernel-0005 pgfincore]$ psql
psql (14.1)
Type "help" for help.
postgres=# create extension pg_buffercache;
CREATE EXTENSION
postgres=# CREATE EXTENSION pgfincore;
CREATE EXTENSION
使用如下语句查看缓存数据量及比例。
postgres=# select c.relname,pg_size_pretty(count(*) * 8192) as pg_buffered,
postgres-# round(100.0 * count(*) /
postgres(# (select setting
postgres(# from pg_settings
postgres(# where name='shared_buffers')::integer,1)
postgres-# as pgbuffer_percent,
postgres-# round(100.0*count(*)*8192 / pg_table_size(c.oid),1) as percent_of_relation,
postgres-# ( select round( sum(pages_mem) * 4 /1024,0 )
postgres(# from pgfincore(c.relname::text) )
postgres-# as os_cache_MB ,
postgres-# round(100 * (
postgres(# select sum(pages_mem)*4096
postgres(# from pgfincore(c.relname::text) )/ pg_table_size(c.oid),1)
postgres-# as os_cache_percent_of_relation,
postgres-# pg_size_pretty(pg_table_size(c.oid)) as rel_size
postgres-# from pg_class c
postgres-# inner join pg_buffercache b on b.relfilenode=c.relfilenode
postgres-# inner join pg_database d on (b.reldatabase=d.oid and d.datname=current_database()
postgres(# and c.relnamespace=(select oid from pg_namespace where nspname='public'))
postgres-# group by c.oid,c.relname
postgres-# order by 3 desc limit 30;
relname | pg_buffered | pgbuffer_percent | percent_of_relation | os_cache_mb | os_cache_percent_of_relation | rel_size
-----------+-------------+------------------+---------------------+-------------+------------------------------+----------
demotable | 43 MB | 33.5 | 100.0 | 43 | 99.9 | 43 MB
demoidx | 64 kB | 0.0 | 0.2 | 30 | 100.0 | 30 MB
(2 rows)
以demotable表为例
pg_buffered表示在PostgreSQL的shared_buffers中缓存了该表多少数据,这里是43MB
pgbuffer_percent 表示是该表占用的shared_buffers的比例,也就是33.5%
percent_of_relation表示表在share_buffers的命中率,这里是100%,
os_cache_mb 表示OS cache中缓存了该表多少数据,这里是43MB
os_cache_percent_of_relation 表示表在OS cache中命中率,这里是99.9%
rel_size 表示这个表的真实大小,这里是43MB
在使用PostgreSQL要设置shared_buffers的大小的时候,我们通常的建议值是操作系统内存的25%,过大或者过小的值都会影响数据库的性能。此时我们有时候会产生一个疑问,为什么类似的参数,ORACLE和MYSQL都分配了操作系统大部分内存,例如ORACLE的sga通常设置为物理内存的80%,或者MySQL的innodb_buffer_pool_size 通常也设置为80%,而PostgreSQL的shared_buffers确设置的比例这么小呢。
pg_shared_plans
/!\此扩展名是POC,尚未准备好生产/!\
pg_shared_plans是一个PostgreSQL扩展,在共享内存中添加了透明的计划缓存。
它可以与本地计划高速缓存管理器的当前基础结构共存,因为尚未被pg_shared_plans高速缓存的计划仍可以被其高速缓存。
此扩展要求安装pg_stat_statements,以便唯一标识标准化的查询。
使用查询标识符不足以唯一地标识一条语句。 根据查询中仍然存在的常量为每个条目计算一个附加的constid哈希。 此外,如果查询依赖于启用行级安全性的关系,则还将记录userid。
与PostgreSQL 12及更高版本兼容
需要PostgreSQL头文件
解压缩tarball或克隆存储库
sudo make install
在shared_preload_libraries中添加pg_shared
postgresql shared_buffers 讲解
什么是shred_buffer,我们为什么需要shared_buffers?
1.在数据库系统中,我们主要关注磁盘io,大多数oltp工作负载都是随机io,因此从磁盘获取非常慢。
2.为了解决这个问题,postgres将数据缓存在RAM中,以此来提高性能,即使ssd的情况下RAM也要快很多。
3.shared_buffers是一个8KB的数组,postgres在从磁盘中查询数据前,会先查找shared_buffers的页,如果命中,就直接返回,避免从
2、为什么要引入shared_buffer?
在数据库系统中,我们主要关注磁盘IO, 大部分oltp工作负载都是随机IO,因此从磁盘获取非常慢。为了解决这个问题,postgre将数据缓存在RAM中,来提高性能。postgresql在查询前,会先查找shared_buffer的页,如果命中,就直接返回,避免从磁盘中查询。
3、为什么要修改shared_buffer参数的值?
shared buffers即数据库服务器的共享内存缓冲区,这个参数一般建议设置成操作系统内存的25%,为什么设置这么大呢?设置的越大是不是越好呢?要解决这些问题,我们需要了解在Postgresql中shared buffers究竟是如何工作的。
再介绍shared buffers之前,我们要先介绍以下postgresql中的bgwriter进程。
bgwriter 负责周期性的将shared buffer中的dirty page刷出shared buffer。这里要注意:bgwriter使用的是buffe
cat /proc/cpuinfo | grep name | cut -f2 -d: | uniq -c
/查看物理CPU个数/
cat /proc/cpuinfo | grep “physical id” | sort -u | wc -l
/查看逻辑CPU个数/
cat /proc/cpuinfo | grep “processor” | wc -l
/查看CPU内核数/
cat /proc/cpuinfo | grep “cpu cores” | uniq
/查看单个物理
c.relname,
pg_size_pretty(count(*) * 8192) as buffered,
round(100.0 * count(*) / (SELECT setting FROM pg_settings WHERE name='shared_buffers')::integer, 1) AS buffer_percent,
round(100.0 * count(*) * 8192 / p
PG的share_buffers设置
注意:配置share_buffers参数时,单位为块,若配置512MB大小,则值应该配置512*1024/8,重启生效
[pg12@wcbpgcm1 log]$ psql
psql (12.9)
Type "help" for help.
postgres=# show shared_buffers ;
shared_buffers
----------------
128MB
(1 row)
postgres=# select * from pg_set