Postgres 9.2'deki work_mem ve shared_buffers'ın arttırılması sorguları önemli ölçüde yavaşlatıyor


39

RHEL 6.3, 16 GB RAM'e sahip 8 çekirdekli bir makinede çalışan bir PostgreSQL 9.2 örneğine sahibim. Sunucu bu veritabanına tahsis edilmiştir. Varsayılan postgresql.conf dosyasının bellek ayarları konusunda oldukça tutucu olduğu göz önüne alındığında, Postgres'in daha fazla bellek kullanmasına izin vermenin iyi bir fikir olduğunu düşündüm. Sürpriz için, wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server adresindeki tavsiyeye uymak , koştuğum her sorguyu pratikte önemli ölçüde yavaşlattı, ancak açıkça daha karmaşık sorgularda farkedilir.

Ayrıca ayarlanan daha fazla parametre ile aşağıdaki tavsiyeyi veren pgtune'u çalıştırmayı denedim, ancak bu hiçbir şeyi değiştirmedi. Başka yerlerdeki tavsiyelere (ve özellikle PG wiki'ye) uygun görünen 1/4 RAM boyutunda paylaşılan kullanıcılar önerir.

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

Ayarları değiştirdikten sonra tüm veritabanını yeniden eklemeyi denedim (kullanarak reindex database), ancak bu da işe yaramadı. Buralarda paylaşılan_buffers ve work_mem ile oynadım. Yavaş yavaş onları çok muhafazakar varsayılan değerlerden (128k / 1MB) değiştirmek yavaş yavaş performansı düşürdü.

Koştum EXPLAIN (ANALYZE,BUFFERS)birkaç sorgularında ve suçlu o Hash önemli ölçüde yavaştır Üyelik gibi görünüyor. Bana neden belli değil.

Belirli bir örnek vermek gerekirse, aşağıdaki sorguyu sahibim. Varsayılan yapılandırmada ~ 2100ms ve tampon boyutu arttırılmış konfigürasyonda ~ 3300ms olarak çalışır:

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) yukarıdaki sorgu için:

Soru, tampon boyutlarını arttırdığımda neden performansın azaldığını gözlemliyorum? Makine kesinlikle belleği tükenmiyor. İşletim sistemi içindeki paylaşılan hafıza ( shmmaxve shmall) çok büyük değerlere ayarlanmışsa, bu bir sorun olmamalıdır. Postgres günlüğünde de hata alamıyorum. Autovacuum'u varsayılan yapılandırmada çalıştırıyorum, ancak bununla bir ilgisi olmasını beklemiyorum. Tüm sorgular aynı makinede birkaç saniye aralıklarla yapıldı, sadece konfigürasyon değişti (ve yeniden başlatılan PG).

Düzenleme: Sadece ilginç bir gerçeği buldum: 2010 ortasıdaki iMac'imde (OSX 10.7.5) aynı testi Postgres 9.2.1 ve 16GB RAM'le aynı testi yaptığımda, yavaşlama deneyimini yaşamadım. özellikle:

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

Sunucuda tam olarak aynı verilerle tam olarak aynı sorguyu yaptığımda (yukarıdakilerden biri), work_mem ile 2100 ms ve 96 MB ile 3200 ms elde ederim.

Mac'te SSD var, bu yüzden anlaşılır bir şekilde daha hızlı, ancak beklediğim bir davranış sergiliyor.

Ayrıca pgsql-performansına ilişkin takip tartışmalarına bakınız .


1
Daha yavaş durumda, her adımın tutarlı bir şekilde yavaş olduğu anlaşılıyor. Diğer ayarlar aynı kaldı mı?
dezso

1
Bunu daha genel bir forumdan ziyade daha uzmanlaşmış bir forumda sormak için zaman ayırmaya değer. Bu durumda pgsql-genel posta listesini öneririm archives.postgresql.org/pgsql-general
Colin 't Hart

1
Oh, ve tekrar rapor edin ve cevabı bulursanız lütfen kendi sorunuza cevap verin! (Buna izin verilir, hatta teşvik edilir).
Colin, Hart,

1
Postgres’in bu konuda Oracle’a ne kadar benzer olduğunu merak ediyorum: Jonathan Lewis’in (Oracle guru) bir dersi hatırlıyorum; bu türlere daha fazla bellek ayırmanın bazen onları yavaşlattığını gösterdi. Ayrıntıları unutuyorum ama Oracle'ın kısmi türler yapması ve sonra bunları geçici depolamaya yazması ve daha sonra bunları birleştirmesiyle ilgisi vardı. Her nasılsa, daha fazla bellek bu işlemi yavaşlattı.
Colin, Hart,

2
Şimdi soru pgsql-performansında yayınlandı: archives.postgresql.org/pgsql-performance/2012-11/msg00004.php
Petr Praus

Yanıtlar:


28

Her şeyden önce, work_mem'in işlem başına olduğunu ve bu sayede oldukça hızlı bir şekilde aşırı olabileceğini unutmayın. Genel olarak, türlerin yavaş olmasıyla ilgili sorun yaşamadığınızda, ihtiyaç duyana kadar work_mem'i yalnız bırakırdım.

Sorgu planlarına baktığımda, beni etkileyen şeylerden biri, tampon vuruşlarının iki plana bakarken çok farklı olduğu ve sıralı taramaların bile daha yavaş olduğu. Konunun ileriye dönük önbellekleme ile ilgisi olduğundan ve bunun için daha az alana sahip olduğundan şüpheleniyorum. Bunun anlamı, indeksleri yeniden kullanmak ve diskteki tabloları okumak için belleği önyargılı hale getirmektir.


Anladığım kadarıyla PostgreSQL'in diskten okumadan önce bir sayfanın önbelleğine bakacağını, çünkü işletim sistemi önbelleğinin o sayfayı içerip içeremeyeceğini bilmiyor. Sayfalar önbellekte kaldığından ve bu önbellek işletim sistemi önbelleğinden daha yavaş olduğundan, bu, hızlı olan sorgulama türlerini yavaşlatır. Aslında çalışmaların okunması, work_mem sorunlarının yanı sıra, tüm sorgu bilgilerinizin önbellekten geldiği anlaşılıyor ancak hangi önbelleğe alındığı sorusu.

work_mem : Bir sıralama veya ilgili birleştirme işlemi için ne kadar bellek ayırabiliriz? Bu işlem başına, ifade başına veya arka uç başına değil, bu nedenle tek bir karmaşık sorgu bu miktardaki belleği birçok kez kullanabilir. Bu sınıra ulaştığınız belli değil, ancak dikkat etmeniz ve farkında olmanıza değer. Bunu çok fazla artırırsanız, okuma önbelleği ve paylaşılan arabellekler için mevcut olan belleği kaybedersiniz.

shared_buffers : Asıl PostgreSQL sayfa sırasına ne kadar bellek ayıracağınız . Şimdi, ideal olarak, veritabanınızın ilginç kümesi burada ve okuma tamponlarında önbelleğe alınmış bellekte kalacaktır. Bununla birlikte, bunun yaptığı şey, tüm arka uçlarda en sık kullanılan bilgilerin önbelleklenip diske atılmamasını sağlamaktır. Linux'ta bu önbellek, OS disk önbelleğinden önemli ölçüde daha yavaştır, ancak OS disk önbelleğinin PostgreSQL için şeffaf ve şeffaf olmadığını garanti eder. Sorunun nerede olduğu açıkça belli.

Öyleyse, bir isteğimiz olduğunda, önce PostgreSQL'in bu önbellek hakkında derin bilgisi olduğundan ve paylaşılan arabellekleri kontrol ettikten sonra paylaşılan arabellekleri kontrol ediyoruz. Eğer orada değillerse, işletim sisteminden onları dosyadan açmasını istiyoruz ve işletim sistemi sonucu önbelleğe aldıysa önbellekteki kopyayı döndürür (bu paylaşılan arabelleklerden daha hızlıdır, ancak Pg önbelleğe alınmış mı yoksa açık mı olduğunu söyleyemez. disk ve disk çok daha yavaştır, bu nedenle PostgreSQL tipik olarak bu şansı kullanmaz. Bunun rastgele vs ardışık sayfa erişimini de etkilediğini unutmayın. Böylece daha düşük paylaşılan_buffers ayarlarıyla daha iyi performans elde edebilirsiniz.

Bağırsak duygum, daha büyük paylaşılan_buffer ayarlarına sahip yüksek eşzamanlılık ortamlarında muhtemelen daha iyi veya en azından daha tutarlı performans elde etmenizdir. Ayrıca PostgreSQL'in bu belleği aldığını ve sistemde çalışan başka şeylerin olması durumunda okuma tamponlarının diğer işlemler tarafından okunan dosyaları tutacağını unutmayın. Bu çok büyük ve karmaşık bir konu. Daha büyük paylaşılan tampon ayarları daha iyi performans garantisi sağlar , ancak bazı durumlarda daha az performans sağlayabilir.


10

Artan work_memperformansı düşüren görünüşte paradoksal etkisinin yanı sıra ( @Chris'in bir açıklaması olabilir), işlevinizi en az iki şekilde geliştirebilirsiniz.

  • İki sahte yeniden yaz LEFT JOIN'ile s JOIN. Bu sorgu planlayıcısının kafasını karıştırabilir ve daha düşük planlara yol açabilir.

SELECT count(*) AS ct
FROM   contest            c
JOIN   contestparticipant cp ON cp.contestId = c.id
JOIN   personinfo         pi ON pi.id = cp.personinfoid
LEFT   JOIN teammember    tm ON tm.contestparticipantid = cp.id
LEFT   JOIN staffmember   sm ON sm.contestparticipantid = cp.id
LEFT   JOIN person        p  ON p.id = cp.personid
WHERE (pi.firstname LIKE '%a%'
OR     pi.lastname  LIKE '%b%')
  • Gerçek arama desenleri üzerinde kullanım trigram endeksleri, daha seçici olduklarını varsayarsak pi.firstnameve pi.lastnamedemirli desteklemek için LIKEaramalar. (Gibi '%a%'daha kısa desenler de desteklenir, ancak bir dizinin seçici olmayan tahminlerde yardımcı olması muhtemel değildir.):

CREATE INDEX personinfo_firstname_gin_idx ON personinfo USING gin (firstname gin_trgm_ops);
CREATE INDEX personinfo_lastname_gin_idx  ON personinfo USING gin (lastname gin_trgm_ops);

Veya bir çoklu sütunlu dizin:

CREATE INDEX personinfo_name_gin_idx ON personinfo USING gin (firstname gin_trgm_ops, lastname gin_trgm_ops);

Sorgunuzu biraz daha hızlı yapmalısınız. Bunun için pg_trgm ek modülünü kurmanız gerekiyor . Bu ilgili soruların altındaki detaylar:


Ayrıca, work_mem yerel olarak ayarlamayı denediniz mi - yalnızca geçerli işlem için ?

SET LOCAL work_mem = '96MB';

Bu, eşzamanlı işlemlerin daha fazla RAM yemesini ve muhtemelen birbirlerini aç bırakmasını önler.


3
Erwin'in yerel çalışma önerisini ikinci kez görmek istiyorum. Work_mem, daha hızlı olan sorgu türlerini değiştirdiğinden, bazı sorgular için bunu değiştirmeniz gerekebilir. Düşük work_mem seviyeleri, en az sayıda kaydı karmaşık şekillerde (örn. Çok sayıda) sıralayan / birleştiren sorgular için en iyisidir; yüksek work_mem düzeyleri ise birkaç türden olan, ancak aynı anda çok sayıda sıraya giren veya katılan sorgular için en iyisidir. .
Chris

Bu arada sorguyu geliştirdim (soru geçen yıl ekim ayından itibaren) ancak teşekkürler :) Bu soru, belirli bir sorgudan çok beklenmeyen etkilerle ilgili. Sorgu temel olarak etkiyi göstermeye yarar. Dizindeki ipucu için teşekkürler, bunu deneyeceğim!
Petr Praus,
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.