it-swarm.asia

Performa Fungsi

Berasal dari latar belakang MySQL, tempat prosedur tersimpan kinerja (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 tentang jebakan kinerja.

53
Derek Downey

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 mereka telah ada di sana dari awal.

Fungsi dengan LANGUAGE sql Pada dasarnya hanya file batch dengan perintah SQL biasa dalam pembungkus fungsi (dan karena itu atomik, selalu dijalankan di dalam single transaksi) menerima parameter. Semua pernyataan dalam fungsi SQL direncanakan sekaligus, yang agak berbeda dari mengeksekusi satu pernyataan setelah yang lain dan dapat memengaruhi urutan pengambilan kunci.

Untuk yang lainnya, bahasa yang paling matang adalah PL/pgSQL (LANGUAGE plpgsql) . Ini berfungsi 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 dalam cache memotong beberapa overhead perencanaan dan membuatnya sedikit lebih cepat daripada 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 - seperti yang dibahas dalam manual . Untuk kueri pada tabel dengan distribusi data tidak teratur dan berbagai parameter SQL dinamis dengan EXECUTE mungkin berkinerja lebih baik ketika keuntungan dari rencana eksekusi yang dioptimalkan untuk parameter yang diberikan lebih besar daripada biaya perencanaan ulang.

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 estimasi biaya rencana umum.

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

Postgres 12 memperkenalkan variabel server tambahan plan_cache_mode untuk memaksa rencana umum atau kustom. Untuk kasus khusus, gunakan dengan hati-hati.

Anda dapat menang besar dengan fungsi sisi server yang mencegah perjalanan 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 Atau 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 exception untuk aturan ini adalah fungsi SQL sederhana (LANGUAGE sql), Yang dapat "inlined" - jika beberapa prasyarat dipenuhi . Baca lebih lanjut tentang cara kerja perencana kueri dalam presentasi ini oleh Neil Conway (hal lanjut).

Dalam PostgreSQL, fungsi selalu berjalan secara otomatis di 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 seperti VACUUM , CREATE INDEX CONCURRENTLY atau CREATE DATABASE tidak dapat 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.

55

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 itu 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. 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 untuk menggunakan fungsi untuk mengimplementasikan pagination karena pagination berbasis kunci bisa lebih cepat daripada pagination berdasarkan LIMIT
  • Pastikan Anda menguji fungsi Anda
12
Neil McGuigan

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 dewasa dan fitur-lengkap dari bahasa built-in - tetapi untuk kinerja, C dapat digunakan ( meskipun hanya akan menguntungkan fungsi intensif komputasi)

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. UDFs yang ditulis dalam C memberi Anda yang terbaik dalam kekuatan dan kinerja, karena mereka berjalan dalam konteks yang sama dengan database 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 seorang programmer Perl 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 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 IO memuat. Namun, jika mereka mulai menambah beban CPU, mereka mungkin menjadi masalah saat itu. Secara umum mengurangi IO memuat adalah prioritas pertama, dan memastikan UDF efisien agar tidak membebani CPU Anda berikutnya.

7
Scott Marlowe