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.
postgresql
best-practices
plpgsql
Derek Downey
sumber
sumber
Jawaban:
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 sql
pada 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
EXECUTE
dapat 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 :
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 server
plan_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 record
atauTABLE (...)
). 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 CONCURRENTLY
atauCREATE DATABASE
tidak 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.
sumber
Beberapa DO:
sumber
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)
sumber
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.
sumber