Saya memiliki instance PostgreSQL 9.2 yang berjalan pada RHEL 6.3, mesin 8-core dengan 16GB RAM. Server didedikasikan untuk basis data ini. Mengingat postgresql.conf default cukup konservatif mengenai pengaturan memori, saya pikir mungkin ide yang baik untuk memungkinkan Postgres menggunakan lebih banyak memori. Yang mengejutkan saya, mengikuti saran di wiki.postgresql.org/wiki/Tuning_Your_PostgreSQL_Server secara signifikan melambat hampir setiap kueri yang saya jalankan tetapi jelas lebih terlihat pada kueri yang lebih kompleks.
Saya juga mencoba menjalankan pgtune yang memberikan rekomendasi berikut dengan lebih banyak parameter yang disetel, tetapi itu tidak mengubah apa pun. Ini menunjukkan shared_buffers dari 1/4 ukuran RAM yang tampaknya sejalan dengan saran di tempat lain (dan pada wiki PG khususnya).
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
Saya mencoba mengindeks ulang seluruh database setelah mengubah pengaturan (menggunakan reindex database
), tetapi itu tidak membantu. Saya bermain-main dengan shared_buffers dan work_mem. Mengubahnya secara bertahap dari nilai standar yang sangat konservatif (128k / 1MB) secara bertahap menurunkan kinerja.
Saya berlari EXPLAIN (ANALYZE,BUFFERS)
pada beberapa pertanyaan dan pelakunya tampaknya Hash Join secara signifikan lebih lambat. Tidak jelas bagi saya mengapa.
Untuk memberikan beberapa contoh spesifik, saya memiliki pertanyaan berikut. Ini berjalan dalam ~ 2100 ms pada konfigurasi default dan ~ 3300 ms pada konfigurasi dengan peningkatan ukuran buffer:
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)
untuk kueri di atas:
- Buffer default: http://explain.depesz.com/s/xaHJ
- Buffer yang lebih besar: http://explain.depesz.com/s/Plk
Pertanyaannya adalah mengapa saya mengamati penurunan kinerja ketika saya meningkatkan ukuran buffer? Mesin pasti tidak kehabisan memori. Alokasi jika memori bersama di OS adalah ( shmmax
dan shmall
) diatur ke nilai yang sangat besar, itu seharusnya tidak menjadi masalah. Saya juga tidak mendapatkan kesalahan dalam log Postgres. Saya menjalankan autovacuum dalam konfigurasi default, tetapi saya tidak berharap ada hubungannya dengan itu. Semua pertanyaan dijalankan pada mesin yang sama beberapa detik terpisah, hanya dengan konfigurasi yang diubah (dan restart PG).
Sunting: Saya baru saja menemukan satu fakta yang sangat menarik: ketika saya melakukan tes yang sama pada pertengahan 2010 iMac (OSX 10.7.5) saya juga dengan Postgres 9.2.1 dan 16GB RAM, saya tidak mengalami perlambatan. Secara khusus:
set work_mem='1MB';
select ...; // running time is ~1800 ms
set work_mem='96MB';
select ...' // running time is ~1500 ms
Ketika saya melakukan permintaan yang persis sama (yang di atas) dengan data yang persis sama di server saya mendapatkan 2100 ms dengan work_mem = 1MB dan 3200 ms dengan 96 MB.
Mac memiliki SSD sehingga bisa dimengerti lebih cepat, tetapi menunjukkan perilaku yang saya harapkan.
Lihat juga diskusi tindak lanjut tentang kinerja pgsql .
sumber
Jawaban:
Pertama-tama, perlu diingat bahwa work_mem adalah per operasi dan sehingga bisa menjadi sangat cepat. Secara umum jika Anda tidak mengalami masalah dengan jenis yang lambat saya akan meninggalkan work_mem sendirian sampai Anda membutuhkannya.
Melihat rencana permintaan Anda, satu hal yang mengejutkan saya adalah bahwa hit buffer sangat berbeda dengan melihat kedua paket tersebut, dan bahkan pemindaian berurutan lebih lambat. Saya menduga bahwa masalah ini berkaitan dengan caching baca-depan dan memiliki lebih sedikit ruang untuk itu. Apa ini artinya Anda biasing memori untuk menggunakan kembali indeks dan terhadap membaca tabel pada disk.
Pemahaman saya adalah PostgreSQL akan melihat ke cache untuk halaman sebelum membacanya dari disk karena tidak tahu benar apakah cache OS akan berisi halaman itu. Karena halaman-halaman tersebut kemudian tinggal di cache dan karena cache itu lebih lambat daripada cache OS, ini mengubah jenis pertanyaan yang cepat vs jenis-jenis yang lambat. Bahkan membaca rencana, selain dari masalah work_mem, sepertinya semua info permintaan Anda berasal dari cache tetapi itu adalah pertanyaan tentang cache yang mana.
work_mem : berapa banyak memori yang dapat kita alokasikan untuk pengurutan atau operasi gabungan yang terkait. Ini adalah per operasi, bukan per pernyataan atau per back-end, jadi satu query kompleks dapat menggunakan banyak kali jumlah memori ini. Tidak jelas Anda mencapai batas ini, tetapi perlu diperhatikan dan diperhatikan. jika Anda meningkatkan ini terlalu jauh, Anda kehilangan memori yang mungkin tersedia untuk cache baca dan buffer bersama.
shared_buffers : berapa banyak memori yang dialokasikan ke antrian halaman PostgreSQL yang sebenarnya. Sekarang, idealnya kumpulan database Anda yang menarik akan tetap tersimpan dalam memori yang tersimpan di sini dan di buffer baca. Namun, yang dilakukan adalah memastikan bahwa informasi yang paling sering digunakan di semua backend di-cache dan tidak dibilas ke disk. Di Linux, cache ini jauh lebih lambat daripada cache disk OS, tetapi cache ini menawarkan jaminan bahwa cache disk OS tidak dan transparan untuk PostgreSQL. Ini cukup jelas di mana masalah Anda.
Jadi yang terjadi adalah ketika kami memiliki permintaan, kami memeriksa buffer bersama terlebih dahulu sejak PostgreSQL memiliki pengetahuan yang mendalam tentang cache ini, dan mencari halaman-halamannya. Jika mereka tidak ada di sana, kami meminta OS untuk membukanya dari file, dan jika OS telah menyimpan hasilnya, ia mengembalikan salinan yang di-cache (ini lebih cepat dari buffer yang dibagikan, tetapi Pg tidak bisa memastikan apakah itu di-cache atau di disk, dan disk jauh lebih lambat sehingga PostgreSQL biasanya tidak akan mengambil risiko itu). Perlu diingat ini juga mempengaruhi akses halaman acak vs berurutan. Jadi, Anda mungkin mendapatkan kinerja yang lebih baik dengan pengaturan shared_buffers yang lebih rendah.
Perasaan saya adalah bahwa Anda mungkin mendapatkan kinerja yang lebih baik, atau setidaknya lebih konsisten, di lingkungan konkurensi tinggi dengan pengaturan shared_buffer yang lebih besar. Juga perlu diingat bahwa PostgreSQL mengambil memori ini dan menahannya jadi jika Anda memiliki hal lain yang berjalan pada sistem, buffer baca akan menahan file yang dibaca oleh proses lain. Ini adalah topik yang sangat besar dan kompleks. Pengaturan buffer bersama yang lebih besar memberikan jaminan kinerja yang lebih baik tetapi dalam beberapa kasus memberikan kinerja yang lebih sedikit.
sumber
Terlepas dari efek yang tampaknya paradoksal yang meningkat
work_mem
penurunan kinerja ( @Chris mungkin memiliki penjelasan), Anda dapat meningkatkan fungsi Anda setidaknya dalam dua cara.LEFT JOIN
denganJOIN
. Itu mungkin membingungkan perencana kueri dan mengarah pada rencana yang lebih rendah.pi.firstname
danpi.lastname
untuk mendukungLIKE
pencarian yang tidak berlabuh . (Pola yang lebih pendek seperti'%a%'
didukung juga tetapi indeks tidak mungkin membantu predikat non-selektif.):Atau satu indeks multikolom:
Seharusnya membuat pertanyaan Anda sedikit lebih cepat. Anda perlu menginstal modul tambahan pg_trgmuntuk ini. Detail di bawah pertanyaan terkait ini:
Juga, sudahkah Anda mencoba pengaturan
work_mem
secara lokal - hanya untuk transaksi saat ini ?Ini menjaga transaksi bersamaan dari juga memakan lebih banyak RAM, mungkin kelaparan satu sama lain.
sumber