postgresql – 在Postgres 9.2上增加work_mem和shared_buffers会大大减慢查询速度

前端之家收集整理的这篇文章主要介绍了postgresql – 在Postgres 9.2上增加work_mem和shared_buffers会大大减慢查询速度前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我有一个在RHEL 6.3上运行的Postgresql 9.2实例,8核机器,16GB内存.服务器专用于此数据库.鉴于默认的 postgresql.conf在内存设置上相当保守,我认为允许Postgres使用更多内存可能是个好主意.令我惊讶的是,遵循 wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server的建议显着减慢了我运行的每个查询,但在更复杂的查询中显然更加明显.

我也试过运行pgtune,它提供了以下建议,调整了更多参数,但这没有改变任何东西.它建议使用1/4 RAM大小的shared_buffers,这似乎符合其他地方的建议(特别是PG维基).

default_statistics_target = 50
maintenance_work_mem = 960MB
constraint_exclusion = on
checkpoint_completion_target = 0.9
effective_cache_size = 11GB
work_mem = 96MB
wal_buffers = 8MB
checkpoint_segments = 16
shared_buffers = 3840MB
max_connections = 80

我尝试在更改设置后重新索引整个数据库(使用reindex数据库),但这也无济于事.我玩过shared_buffers和work_mem.逐渐从非常保守的默认值(128k / 1MB)改变它们逐渐降低性能.

我在几个查询上运行了EXPLAIN(ANALYZE,BUFFERS),罪魁祸首似乎是Hash Join明显变慢了.我不清楚为什么.

举一些具体的例子,我有以下查询.它在默认配置下运行~2100ms,在配置上运行~3300ms,缓冲区大小增加

select count(*) from contest c
left outer join contestparticipant cp on c.id=cp.contestId
left outer join teammember tm on tm.contestparticipantid=cp.id
left outer join staffmember sm on cp.id=sm.contestparticipantid
left outer join person p on p.id=cp.personid
left outer join personinfo pi on pi.id=cp.personinfoid
where pi.lastname like '%b%' or pi.firstname like '%a%';

上述查询的EXPLAIN(ANALYZE,BUFFERS):

>默认缓冲区:http://explain.depesz.com/s/xaHJ
>更大的缓冲区:http://explain.depesz.com/s/Plk

问题是,当我增加缓冲区大小时,为什么我观察到性能下降?机器肯定没有内存不足.如果OS中的共享内存(shmmax和shmall)的分配设置为非常大的值,那应该不是问题.我也没有在Postgres日志中收到任何错误.我在默认配置中运行autovacuum,但我不认为它与它有任何关系.所有查询都在几秒钟内在同一台机器上运行,只需更改配置(并重新启动PG).

编辑:
我刚刚发现了一个特别有趣的事实:当我在2010年中期的iMac(OSX 10.7.5)上使用Postgres 9.2.1和16GB RAM执行相同的测试时,我没有遇到减速.
特别:

set work_mem='1MB';
select ...; // running time is ~1800 ms
set work_mem='96MB';
select ...' // running time is ~1500 ms

当我在服务器上执行完全相同的查询(上面的查询)时,我得到2100毫秒,work_mem = 1MB,3200毫秒,96 MB.

Mac有SSD,因此可以理解的速度更快,但它表现出我期望的行为.

另见follow-up discussion on pgsql-performance.

首先,请记住work_mem是每个操作,所以它可以很快地过度.一般情况下,如果你没有遇到麻烦,我会单独留下work_mem,直到你需要它为止.

看看你的查询计划,有一件事让我印象深刻,看两个计划的缓冲区命中是非常不同的,甚至连续扫描都比较慢.我怀疑这个问题与预读缓存有关,并且空间较小.这意味着你是在为重用索引和反对在磁盘上读表而偏置内存.

我的理解是Postgresql在从磁盘读取之前会查找页面的缓存,因为它不知道操作系统缓存是否会包含该页面.因为页面然后停留在缓存中,并且因为缓存比OS缓存慢,所以这会更改快速查询的类型.事实上,除了work_mem问题之外,阅读计划看起来所有的查询信息都来自缓存,但这是一个关于哪个缓存的问题.

work_mem:我们可以为排序或相关的连接操作分配多少内存.这是每个操作,而不是每个语句或每个后端,因此单个复杂查询可以使用此数量的内存.目前尚不清楚你是否达到了这个限制,但值得注意并注意到.如果增加太多,则会丢失可用于读取缓存和共享缓冲区的内存.

shared_buffers:分配给实际Postgresql页面队列的内存量.现在,理想情况下,数据库的有趣集合将保留在此处和读取缓冲区中缓存的内存中.但是,这样做可确保所有后端中最常用的信息得到缓存而不会刷新到磁盘.在Linux上,这个缓存明显慢于操作系统磁盘缓存,但它保证了操作系统磁盘缓存不会对Postgresql透明.这显然是你的问题所在.

所以当我们有一个请求时,我们首先检查共享缓冲区,因为Postgresql对这个缓存有深入的了解,并查找这些页面.如果它们不存在,我们要求操作系统从文件中打开它们,如果操作系统缓存了结果,则返回缓存副本(这比共享缓冲区快,但Pg无法判断它是缓存还是磁盘和磁盘要慢得多,所以Postgresql通常不会抓住这个机会).请记住,这也会影响随机页面和顺序页面访问.因此,使用较低的shared_buffers设置可以获得更好的性能.

我的直觉是,在具有更大shared_buffer设置的高并发环境中,您可能会获得更好或至少更一致的性能.还要记住Postgresql抓住这个内存并保留它,所以如果你在系统上运行其他东西,读缓冲区将保存其他进程读取的文件.这是一个非常庞大而复杂的话题.较大的共享缓冲区设置可提供更好的性能保证,但在某些情况下可能会降低性能.

猜你在找的Postgre SQL相关文章