Optimalkan PostgreSQL untuk pengujian cepat

203

Saya beralih ke PostgreSQL dari SQLite untuk aplikasi Rails yang khas.

Masalahnya adalah bahwa spesifikasi berjalan lambat dengan PG.
Pada SQLite butuh ~ 34 detik, pada PG itu ~ 76 detik yang lebih dari 2x lebih lambat .

Jadi sekarang saya ingin menerapkan beberapa teknik untuk membawa kinerja spesifikasi setara dengan SQLite tanpa modifikasi kode (idealnya hanya dengan mengatur opsi koneksi, yang mungkin tidak mungkin).

Beberapa hal yang jelas dari kepala saya adalah:

  • RAM Disk (setup yang baik dengan RSpec pada OSX akan bagus untuk dilihat)
  • Tabel tidak terdaftar (dapatkah diterapkan pada seluruh basis data sehingga saya tidak mengubah semua skrip?)

Seperti yang mungkin sudah Anda pahami, saya tidak peduli dengan keandalan dan sisanya (DB hanyalah benda yang bisa dibuang di sini).
Saya perlu mendapatkan hasil maksimal dari PG dan membuatnya secepat mungkin .

Jawaban terbaik idealnya menggambarkan trik untuk melakukan hal itu, pengaturan dan kelemahan dari trik itu.

UPDATE: fsync = off + full_page_writes = offhanya mengurangi waktu hingga ~ 65 detik (~ -16 detik). Awal yang bagus, tetapi jauh dari target 34.

UPDATE 2: Saya mencoba menggunakan RAM disk tetapi kenaikan kinerja berada dalam margin kesalahan. Jadi sepertinya tidak sepadan.

UPDATE 3: * Saya menemukan hambatan terbesar dan sekarang spesifikasi saya berjalan secepat yang SQLite.

Masalahnya adalah pembersihan basis data yang melakukan pemotongan . Rupanya SQLite terlalu cepat di sana.

Untuk "memperbaikinya", saya membuka transaksi sebelum setiap tes dan mengembalikannya di akhir.

Beberapa angka untuk ~ 700 tes.

  • Pemotongan: SQLite - 34s, PG - 76s.
  • Transaksi: SQLite - 17s, PG - 18s.

Peningkatan kecepatan 2x untuk SQLite. Peningkatan kecepatan 4x untuk PG.

Dmytrii Nagirniak
sumber
2
Saya benar-benar ragu Anda akan mendapatkannya secepat SQLite. SQLite dengan satu pengguna sangat cepat. Desain SQLite sangat cepat dengan jumlah dan skala pengguna yang rendah; Desain Pg berskala baik tetapi tidak secepat untuk pekerjaan massal sederhana hanya dengan satu pengguna.
Craig Ringer
1
Saya menyadari hal itu, tetapi ada kasus khusus yang saya harap dapat mengoptimalkan PG untuk (uji coba) sehingga secepat mungkin. Saya tidak keberatan untuk menjadi sedikit lebih lambat di sana, tetapi 2.2x agak terlalu lambat. Lihat apa yang saya maksud?
Dmytrii Nagirniak
+1 Saya akan sangat tertarik dengan pembaruan pada pendekatan disk RAM jika Anda mendapatkan hasil apa pun tentang itu.
tscho
@tscho saya pasti akan mempostingnya di sini. Tetapi perlu waktu karena saya sedang mengerjakan hal-hal lain dan "meneliti" hal-hal PG di "latar belakang".
Dmytrii Nagirniak
adalah memasukkan data masalah atau query ? Tidak jelas dari pertanyaan Anda.
a_horse_with_no_name

Jawaban:

281

Pertama, selalu gunakan versi terbaru dari PostgreSQL. Peningkatan kinerja selalu datang, jadi Anda mungkin membuang-buang waktu jika menyetel versi lama. Sebagai contoh, PostgreSQL 9.2 secara signifikan meningkatkan kecepatanTRUNCATE dan tentu saja menambahkan hanya scan indeks. Bahkan rilis kecil harus selalu diikuti; lihat kebijakan versi .

Larangan

Apakah tidak menaruh tablespace pada RAMdisk atau penyimpanan non-tahan lama lainnya .

Jika Anda kehilangan tablespace seluruh database mungkin rusak dan sulit digunakan tanpa kerja yang signifikan. Ada sedikit keuntungan untuk ini dibandingkan dengan hanya menggunakan UNLOGGEDtabel dan memiliki banyak RAM untuk cache.

Jika Anda benar-benar menginginkan sistem berbasis ramdisk, initdbseluruh cluster baru pada ramdisk dengan initdbmemasukkan instance PostgreSQL baru pada ramdisk, sehingga Anda memiliki instance PostgreSQL sekali pakai.

Konfigurasi server PostgreSQL

Saat menguji, Anda dapat mengonfigurasi server Anda untuk pengoperasian yang tidak tahan lama namun lebih cepat .

Ini adalah satu-satunya kegunaan yang dapat diterima untuk fsync=offpengaturan di PostgreSQL. Pengaturan ini cukup banyak memberi tahu PostgreSQL untuk tidak repot-repot dengan perintah yang tertulis atau hal-hal buruk lainnya seperti integritas data, perlindungan, dan keamanan kecelakaan, yang memberikan izin untuk benar-benar membuang data Anda jika Anda kehilangan daya atau mengalami gangguan OS.

Tidak perlu dikatakan, Anda tidak boleh mengaktifkan fsync=offproduksi kecuali Anda menggunakan Pg sebagai basis data sementara untuk data yang dapat Anda hasilkan kembali dari tempat lain. Jika dan hanya jika Anda melakukan untuk mematikan fsync juga dapat full_page_writesmematikan, karena tidak ada gunanya lagi. Berhati-hatilah fsync=offdan full_page_writesterapkan pada level cluster , sehingga memengaruhi semua database dalam instance PostgreSQL Anda.

Untuk penggunaan produksi Anda mungkin dapat menggunakan synchronous_commit=offdan mengatur commit_delay, karena Anda akan mendapatkan banyak manfaat yang sama seperti fsync=offtanpa risiko korupsi data raksasa. Anda memiliki jendela kecil hilangnya data terbaru jika Anda mengaktifkan async commit - tetapi hanya itu.

Jika Anda memiliki opsi untuk sedikit mengubah DDL, Anda juga dapat menggunakan UNLOGGEDtabel di Pg 9.1+ untuk sepenuhnya menghindari logging WAL dan mendapatkan peningkatan kecepatan nyata dengan biaya tabel yang terhapus jika server crash. Tidak ada opsi konfigurasi untuk membuat semua tabel tidak masuk log, harus disetel selama CREATE TABLE. Selain bagus untuk pengujian, ini berguna jika Anda memiliki tabel yang penuh dengan data yang dihasilkan atau tidak penting dalam database yang jika tidak berisi hal-hal yang Anda butuhkan agar aman.

Periksa log Anda dan lihat apakah Anda mendapat peringatan tentang terlalu banyak pos pemeriksaan. Jika ya, Anda harus meningkatkan checkpoint_segments Anda . Anda mungkin juga ingin menyetel checkpoint_completion_target Anda untuk memperlancar penulisan.

Tune shared_buffersagar sesuai dengan beban kerja Anda. Ini tergantung pada OS, tergantung pada apa lagi yang terjadi dengan mesin Anda, dan memerlukan beberapa trial and error. Standarnya sangat konservatif. Anda mungkin perlu meningkatkan batas memori bersama maksimum OS jika Anda meningkatkan shared_bufferspada PostgreSQL 9.2 dan di bawahnya; 9.3 dan di atas mengubah cara mereka menggunakan memori bersama untuk menghindarinya.

Jika Anda hanya menggunakan beberapa koneksi yang banyak bekerja, tingkatkan work_memuntuk memberi mereka lebih banyak RAM untuk bermain bersama dll. Hati-hati karena work_mempengaturan yang terlalu tinggi dapat menyebabkan masalah kehabisan memori karena per-sort tidak per-koneksi sehingga satu kueri dapat memiliki banyak jenis bersarang. Anda hanya benar - benar harus meningkatkan work_memjika Anda dapat melihat jenis tumpah ke disk EXPLAINatau masuk dengan log_temp_filespengaturan (disarankan), tetapi nilai yang lebih tinggi juga dapat membiarkan Pg memilih paket yang lebih cerdas.

Seperti yang dikatakan oleh poster lain di sini adalah bijaksana untuk meletakkan xlog dan tabel / indeks utama pada HDD terpisah jika memungkinkan. Partisi yang terpisah tidak ada gunanya, Anda benar-benar menginginkan drive yang terpisah. Pemisahan ini memiliki manfaat yang jauh lebih kecil jika Anda menjalankan fsync=offdan hampir tidak ada jika Anda menggunakan UNLOGGEDtabel.

Akhirnya, sesuaikan kueri Anda. Pastikan bahwa Anda random_page_costdan seq_page_costmencerminkan kinerja sistem Anda, pastikan Anda effective_cache_sizebenar, dll. Gunakan EXPLAIN (BUFFERS, ANALYZE)untuk memeriksa setiap rencana kueri, dan nyalakan auto_explainmodul untuk melaporkan semua permintaan yang lambat. Anda sering dapat meningkatkan kinerja permintaan secara dramatis hanya dengan membuat indeks yang sesuai atau mengubah parameter biaya.

AFAIK tidak ada cara untuk mengatur seluruh database atau cluster UNLOGGED. Sangat menarik untuk bisa melakukannya. Pertimbangkan untuk bertanya pada milis PostgreSQL.

Host OS tuning

Ada beberapa penyetelan yang dapat Anda lakukan di level sistem operasi juga. Hal utama yang Anda mungkin ingin lakukan adalah meyakinkan sistem operasi untuk tidak menyiram menulis ke disk secara agresif, karena Anda benar-benar tidak peduli kapan / jika mereka membuatnya ke disk.

Di Linux Anda dapat mengontrol ini dengan memori virtual subsistem 's dirty_*pengaturan, seperti dirty_writeback_centisecs.

Satu-satunya masalah dengan menyetel pengaturan penulisan kembali menjadi terlalu kendur adalah bahwa flush oleh beberapa program lain dapat menyebabkan semua buffer yang terkumpul PostgreSQL juga memerah, menyebabkan warung besar sementara semuanya terhenti pada penulisan. Anda mungkin dapat mengatasi ini dengan menjalankan PostgreSQL pada sistem file yang berbeda, tetapi beberapa flushes mungkin tingkat perangkat atau tingkat host-bukan tingkat sistem file, sehingga Anda tidak dapat mengandalkan itu.

Penyesuaian ini benar-benar mengharuskan Anda bermain-main dengan pengaturan untuk melihat mana yang paling cocok untuk beban kerja Anda.

Pada kernel yang lebih baru, Anda mungkin ingin memastikan bahwa vm.zone_reclaim_modediatur ke nol, karena dapat menyebabkan masalah kinerja yang parah dengan sistem NUMA (sebagian besar sistem saat ini) karena interaksi dengan bagaimana PostgreSQL mengelola shared_buffers.

Penyetelan kueri dan beban kerja

Ini adalah hal-hal yang DO memerlukan perubahan kode; mereka mungkin tidak cocok untuk Anda. Beberapa hal yang mungkin bisa Anda terapkan.

Jika Anda tidak mengelompokkan pekerjaan menjadi transaksi yang lebih besar, mulailah. Banyak transaksi kecil mahal, jadi Anda harus mengumpulkan barang kapan pun memungkinkan dan praktis untuk melakukannya. Jika Anda menggunakan komit async, ini kurang penting, tetapi masih sangat disarankan.

Kapan saja memungkinkan gunakan tabel sementara. Mereka tidak menghasilkan lalu lintas WAL, jadi mereka jauh lebih cepat untuk menyisipkan dan memperbarui. Kadang-kadang ada baiknya menyeruput sekelompok data ke tabel temp, memanipulasi sesuka Anda, lalu melakukan itu INSERT INTO ... SELECT ...untuk menyalinnya ke tabel final. Perhatikan bahwa tabel sementara adalah per sesi; jika sesi Anda berakhir atau Anda kehilangan koneksi Anda maka tabel temp hilang, dan tidak ada koneksi lain dapat melihat isi dari tabel temp sesi (s).

Jika Anda menggunakan PostgreSQL 9.1 atau yang lebih baru, Anda bisa menggunakan UNLOGGEDtabel untuk data yang bisa Anda hilangkan, seperti status sesi. Ini terlihat di berbagai sesi dan dipertahankan di antara koneksi. Mereka terpotong jika server dimatikan dengan tidak jelas sehingga mereka tidak dapat digunakan untuk apa pun yang tidak dapat Anda buat kembali, tetapi mereka bagus untuk cache, tampilan terwujud, tabel negara, dll.

Secara umum, jangan DELETE FROM blah;. Gunakan TRUNCATE TABLE blah;sebaliknya; itu jauh lebih cepat ketika Anda membuang semua baris dalam sebuah tabel. Potong banyak tabel dalam satu TRUNCATEpanggilan jika Anda bisa. Ada peringatan jika Anda melakukan banyak TRUNCATEStabel kecil berulang kali; lihat: Kecepatan pemotongan Postgresql

Jika Anda tidak memiliki indeks pada kunci asing, DELETEmelibatkan kunci primer yang dirujuk oleh kunci asing itu akan sangat lambat. Pastikan untuk membuat indeks seperti itu jika Anda mengharapkan DELETEdari tabel yang direferensikan. Indeks tidak diperlukan untuk TRUNCATE.

Jangan membuat indeks yang tidak Anda butuhkan. Setiap indeks memiliki biaya perawatan. Cobalah untuk menggunakan satu set indeks minimal dan biarkan scan indeks bitmap menggabungkannya daripada mempertahankan terlalu banyak indeks multi-kolom yang besar dan mahal. Di mana indeks diperlukan, cobalah untuk mengisi tabel terlebih dahulu, lalu buat indeks di akhir.

Perangkat keras

Memiliki cukup RAM untuk menampung seluruh basis data adalah kemenangan besar jika Anda dapat mengelolanya.

Jika Anda tidak memiliki cukup RAM, semakin cepat penyimpanan Anda bisa mendapatkan yang lebih baik. Bahkan SSD yang murah membuat perbedaan besar pada karat yang berputar. Jangan percaya SSD murah untuk produksi, mereka sering tidak crashsafe dan mungkin memakan data Anda.

Belajar

Buku Greg Smith, PostgreSQL 9.0 High Performance tetap relevan meskipun merujuk pada versi yang agak lama. Ini harus menjadi referensi yang bermanfaat.

Bergabunglah dengan milis umum PostgreSQL dan ikuti.

Bacaan:

Craig Ringer
sumber
10
Saya juga dapat merekomendasikan PostgreSQL 9.0 High Performance oleh @GregSmith, ini benar-benar bacaan yang bagus. Buku ini mencakup setiap aspek penyetelan kinerja dari tata letak disk hingga penyetelan kueri dan memberi Anda pemahaman yang sangat baik tentang internal PG.
tscho
10
Saya tidak merilis pembaruan untuk buku untuk PostgreSQL 9.1, satu-satunya rilis sejak publikasi, karena tidak ada perubahan terkait kinerja yang cukup di 9,1 untuk menjaminnya.
Greg Smith
3
Langgan yang bagus. Sama seperti pembaruan kecil, “Anda mungkin perlu meningkatkan batas memori bersama maksimum OS jika Anda menambah shared_buffers” tidak lagi benar (untuk sebagian besar pengguna) di bawah PostgreSQL 9.3: postgresql.org/docs/9.3/static/release-9- 3.html # AEN114343
Gunnlaugur Briem
1
@ Brauliobo Tes saya sering melakukan banyak hal di TPS tinggi ... karena saya mencoba mensimulasikan produksi, termasuk beban kerja yang sangat berat. Jika Anda maksud "koneksi tunggal, pengujian linier" maka saya akan setuju dengan Anda.
Craig Ringer
1
stackoverflow.com/questions/11419536/... DELETE mungkin lebih cepat daripada TRUNCATE untuk tabel dengan beberapa baris, yang mungkin merupakan kasus dalam pengujian.
Jonathan Crosmer
9

Gunakan tata letak disk yang berbeda:

  • disk berbeda untuk $ PGDATA
  • disk berbeda untuk $ PGDATA / pg_xlog
  • disk berbeda untuk file tem (per database $ PGDATA / base // pgsql_tmp) (lihat catatan tentang work_mem)

postgresql.conf tweak:

  • shared_memory: 30% dari RAM yang tersedia tetapi tidak lebih dari 6 hingga 8GB. Tampaknya lebih baik memiliki lebih sedikit memori bersama (2GB - 4GB) untuk beban kerja tulis yang intensif
  • work_mem: sebagian besar untuk kueri pemilihan dengan macam / agregasi. Ini adalah per pengaturan koneksi dan permintaan dapat mengalokasikan nilai itu beberapa kali. Jika data tidak cocok maka disk digunakan (pgsql_tmp). Periksa "jelaskan analisis" untuk melihat berapa banyak memori yang Anda butuhkan
  • fsync dan syncous_commit: Nilai default aman tetapi jika Anda dapat mentolerir data yang hilang maka Anda dapat mematikan kemudian
  • random_page_cost: jika Anda memiliki SSD atau larik RAID cepat, Anda dapat menurunkan ini ke 2.0 (RAID) atau bahkan lebih rendah (1.1) untuk SSD
  • checkpoint_segments: Anda bisa naik lebih tinggi 32 atau 64 dan mengubah checkpoint_completion_target menjadi 0,9. Nilai yang lebih rendah memungkinkan pemulihan pasca-kecelakaan yang lebih cepat
milikku
sumber
4
Perhatikan bahwa jika Anda sudah menjalankannya fsync=off, meletakkan pg_xlog pada disk terpisah tidak banyak membaik lagi.
intgr
Nilai 1.1 untuk SSD tampaknya sangat tidak memenuhi syarat. Saya mengakui bahwa itulah yang direkomendasikan oleh beberapa profesional secara membabi buta. Bahkan SSD secara signifikan lebih cepat untuk pembacaan berurutan daripada pembacaan acak.
Acumenus
@ ABB Ya, tetapi Anda juga punya efek caching buffer OS di tempat kerja. Lagipula semua param itu agak lamban ...
Craig Ringer