Performa Fungsi

46

Berasal dari latar belakang MySQL, di mana kinerja prosedur tersimpan (artikel lama) dan kegunaan dipertanyakan, saya mengevaluasi PostgreSQL untuk produk baru untuk perusahaan saya.

Salah satu hal yang ingin saya lakukan adalah memindahkan beberapa logika aplikasi ke dalam prosedur tersimpan, jadi saya di sini meminta DO dan DON'Ts (praktik terbaik) tentang penggunaan fungsi di PostgreSQL (9.0), khususnya mengenai jebakan kinerja.

Derek Downey
sumber
maksud Anda Anda tidak ingin jawaban menyebutkan sesuatu yang tidak terkait kinerja?
Jack Douglas
Blog Chris Travers banyak tentang keuntungan menggunakan prosedur tersimpan, misal di sini: ledgersmbdev.blogspot.de/2012/07/… dan di sini: ledgersmbdev.blogspot.de/2012/07/… cukup membaca blognya, ada banyak artikel menarik tentang topik ini.
a_horse_with_no_name

Jawaban:

51

Sebenarnya, istilah "prosedur tersimpan" menunjuk ke prosedur SQL di Postgres, diperkenalkan dengan Postgres 11. Terkait:

Ada juga fungsi , melakukan hampir tetapi tidak persis sama, dan itu sudah ada sejak awal.

Fungsi - fungsi dengan LANGUAGE sqlpada dasarnya hanyalah file batch dengan perintah SQL biasa dalam fungsi wrapper (dan karena itu atomik, selalu dijalankan dalam satu transaksi tunggal ) menerima parameter. Semua pernyataan dalam fungsi SQL direncanakan sekaligus , yang agak berbeda dari mengeksekusi satu pernyataan setelah yang lain dan dapat mempengaruhi urutan pengambilan kunci.

Untuk yang lainnya, bahasa yang paling matang adalah PL / pgSQL ( LANGUAGE plpgsql). Ini bekerja dengan baik dan telah ditingkatkan dengan setiap rilis selama dekade terakhir, tetapi berfungsi terbaik sebagai lem untuk perintah SQL. Ini tidak dimaksudkan untuk perhitungan berat (selain dengan perintah SQL).

Fungsi PL / pgSQL menjalankan query seperti pernyataan yang disiapkan . Menggunakan kembali rencana permintaan yang di-cache memotong beberapa overhead perencanaan dan membuatnya sedikit lebih cepat dari pernyataan SQL yang setara, yang mungkin merupakan efek yang terlihat tergantung pada keadaan. Mungkin juga memiliki efek samping seperti dalam pertanyaan terkait ini:

Ini membawa kelebihan dan kekurangan dari pernyataan yang disiapkan - sebagaimana dibahas dalam manual . Untuk query pada tabel dengan distribusi data yang tidak teratur dan bervariasi parameter SQL dinamis dengan EXECUTEdapat melakukan lebih baik ketika keuntungan dari rencana eksekusi dioptimalkan untuk parameter yang diberikan (s) melebihi biaya re-perencanaan.

Karena Postgres 9.2 rencana eksekusi umum masih di-cache untuk sesi ini tetapi, mengutip manual :

Ini terjadi segera untuk pernyataan yang disiapkan tanpa parameter; jika tidak, itu terjadi hanya setelah lima atau lebih eksekusi menghasilkan rencana yang perkiraan biaya rata-rata (termasuk biaya overhead perencanaan) lebih mahal daripada perkiraan biaya rencana umum.

Kami mendapatkan yang terbaik dari kedua dunia sebagian besar waktu (kurang beberapa overhead tambahan) tanpa menggunakan (ab) EXECUTE. Detail dalam Apa yang baru di PostgreSQL 9.2 dari PostgreSQL Wiki .

Postgres 12 memperkenalkan variabel serverplan_cache_mode tambahan untuk memaksa paket generik atau kustom. Untuk kasus khusus, gunakan dengan hati-hati.

Anda dapat menang besar dengan fungsi-fungsi sisi server yang mencegah bolak- balik tambahan ke server database dari aplikasi Anda. Mintalah server mengeksekusi sebanyak mungkin sekaligus dan hanya mengembalikan hasil yang terdefinisi dengan baik.

Hindari bersarang fungsi kompleks, terutama fungsi tabel ( RETURNING SETOF recordatau TABLE (...)). Fungsinya adalah kotak hitam yang menyamar sebagai penghalang optimasi perencana kueri. Mereka dioptimalkan secara terpisah, bukan dalam konteks permintaan luar, yang membuat perencanaan lebih sederhana, tetapi dapat menghasilkan rencana yang kurang sempurna. Juga, biaya dan hasil ukuran fungsi tidak dapat diprediksi dengan andal.

The pengecualian untuk aturan ini adalah fungsi SQL sederhana ( LANGUAGE sql), yang dapat "inline" - jika beberapa prasyarat terpenuhi . Baca selengkapnya tentang cara kerja perencana kueri dalam presentasi ini oleh Neil Conway (hal lanjut).

Dalam PostgreSQL, fungsi selalu berjalan secara otomatis dalam satu transaksi . Semua itu berhasil atau tidak sama sekali. Jika pengecualian terjadi, semuanya dibatalkan. Tetapi ada penanganan kesalahan ...

Itu juga sebabnya fungsi tidak persis "prosedur tersimpan" (meskipun istilah itu kadang-kadang digunakan, menyesatkan). Beberapa perintah suka VACUUM, CREATE INDEX CONCURRENTLYatau CREATE DATABASEtidak bisa berjalan di dalam blok transaksi, sehingga tidak diizinkan dalam fungsi. (Baik dalam prosedur SQL, belum, pada Postgres 11. Itu mungkin ditambahkan nanti.)

Saya telah menulis ribuan fungsi plpgsql selama bertahun-tahun.

Erwin Brandstetter
sumber
2
@nhahtdh: "transaksi otomatis" bukan istilah teknis. Itu hanya cara yang tidak elegan untuk mengatakan .. apa yang dikatakannya sekarang setelah klarifikasi saya. Sama sekali bukan transaksi otonom. "otonom" kebetulan merupakan kata yang mirip.
Erwin Brandstetter
4
Jawaban Anda dikompilasi dari sini dan SO bisa menjadi buku pegangan praktik terbaik PostGreSQL.
Davos
10

Beberapa DO:

  • Gunakan SQL sebagai bahasa fungsi bila memungkinkan, karena PG dapat inline pernyataan
  • Gunakan IMMUTABLE / STABLE / VOLATILE dengan benar, karena PG dapat men-cache hasil jika tidak berubah atau stabil
  • Gunakan STRICT dengan benar, karena PG hanya dapat mengembalikan nol jika ada input yang bukan menjalankan fungsi
  • Pertimbangkan PL / V8 ketika Anda tidak dapat menggunakan SQL sebagai bahasa fungsi. Ini lebih cepat daripada PL / pgSQL dalam beberapa tes tidak ilmiah yang saya jalankan
  • Gunakan DENGARKAN / PEMBERITAHUAN untuk proses yang berjalan lebih lama yang dapat terjadi di luar transaksi
  • Pertimbangkan menggunakan fungsi untuk mengimplementasikan pagination karena pagination berbasis kunci bisa lebih cepat daripada pagination berdasarkan LIMIT
  • Pastikan Anda menguji fungsi Anda
Neil McGuigan
sumber
Ini pertama kalinya saya melihat klaim bahwa PL / V8 lebih cepat dari PL / pgSQL. Apakah Anda memiliki angka (yang dipublikasikan) untuk mendukungnya?
a_horse_with_no_name
@a_horse_with_no_name tidak, saya tidak. Seperti yang saya katakan, saya melakukan beberapa tes tidak ilmiah. Mereka sebagian besar logika, bukan akses data. Saya akan mencoba melakukan beberapa tes berulang di atas xmas dan memposting ulang di sini.
Neil McGuigan
@a_horse_with_no_name inilah contoh cepat-n-kotor untuk FizzBuzz plv8 vs plpgsql: blog.databasepatterns.com/2014/08/plv8-vs-plpgsql.html
Neil McGuigan
8

Secara umum, memindahkan logika aplikasi ke dalam basis data akan berarti lebih cepat - setelah semua itu akan berjalan lebih dekat ke data.

Saya percaya (tapi saya tidak 100% yakin) bahwa fungsi bahasa SQL lebih cepat daripada yang menggunakan bahasa lain karena mereka tidak memerlukan pengalihan konteks. Kelemahannya adalah tidak ada logika prosedural yang diizinkan.

PL / pgSQL adalah yang paling matang dan fitur-lengkap dari bahasa built-in - tetapi untuk kinerja, C dapat digunakan (meskipun hanya akan menguntungkan fungsi intensif komputasi)

Jack Douglas
sumber
7

Anda dapat melakukan beberapa hal yang sangat menarik menggunakan fungsi yang ditentukan pengguna (UDF) di postgresql. Misalnya, ada puluhan bahasa yang mungkin dapat Anda gunakan. Built in pl / sql dan pl / pgsql keduanya mampu dan dapat diandalkan dan menggunakan metode kotak pasir untuk menjaga pengguna dari melakukan sesuatu yang terlalu berbahaya. UDF yang ditulis dalam C memberi Anda kekuatan dan kinerja tertinggi, karena dijalankan dalam konteks yang sama dengan basis data itu sendiri. Namun, ini seperti bermain api, karena kesalahan kecil pun dapat menyebabkan masalah besar, dengan backend crash atau data menjadi rusak. Bahasa custome pl, seperti pl / R, pl / ruby, pl / perl, dan sebagainya memberi Anda kemampuan untuk menulis kedua basis data dan lapisan aplikasi dalam bahasa yang sama. Ini bisa berguna, karena itu berarti Anda tidak perlu mengajar programmer java atau pl / pgsql dll untuk menulis UDF.

Terakhir, ada bahasa pl / proxy . Bahasa UDF ini memungkinkan Anda untuk menjalankan aplikasi Anda di banyak server postgresql backend atau lebih untuk tujuan penskalaan. Ini dikembangkan oleh orang-orang baik di Skype dan pada dasarnya memungkinkan untuk solusi penskalaan horizontal orang miskin. Sangat mudah juga untuk menulis.

Sekarang, tentang masalah kinerja. Ini adalah area abu-abu. Apakah Anda menulis aplikasi untuk satu orang? Atau 1.000? atau untuk 10.000.000? Cara Anda membangun aplikasi dan menggunakan UDF akan sangat bergantung pada cara Anda mengukur. Jika Anda menulis untuk ribuan dan ribuan pengguna, maka hal utama yang ingin Anda lakukan adalah mengurangi beban pada db sebanyak mungkin. UDF yang mengurangi jumlah data yang dipindahkan dan kembali ke database akan membantu mengurangi beban IO. Namun, jika mereka mulai menambah beban CPU, mereka mungkin menjadi masalah kemudian. Secara umum mengurangi beban IO adalah prioritas pertama, dan memastikan UDF efisien agar tidak membebani CPU Anda berikutnya.

Scott Marlowe
sumber