Jadi, pertanyaan Anda akhirnya bermuara pada "bagaimana java.sql.PreparedStatement
bermain dengan PostgreSQL". Lihat jawaban tentang "bagaimana ini dimainkan dengan paket yang disiapkan server" di bagian akhir.
Inilah jawabannya:itu tergantung pada driver JDBC yang Anda gunakan.
TL;DR :dalam driver modern, pernyataan yang disiapkan server akan tetap hidup hingga koneksi mati atau hingga pernyataan digusur oleh pernyataan lain (pengusiran LRU biasa).
Catatan:Server PostgreSQL tidak dapat membagikan pernyataan yang telah disiapkan di seluruh koneksi database, sehingga driver JDBC terbaik yang dapat dilakukan adalah menyimpan rencana dalam cache di setiap koneksi.
Catatan:Spesifikasi JDBC mengamanatkan penggunaan ?, ?
untuk mengikat placeholder, sementara server menginginkan $1, $2
jadi driver JDBC juga menyimpan apa yang disebut teks SQL yang diurai.
Ada dua driver JDBC yang terkenal:pgjdbc dan pgjdbc-ng
pgjdbc
https://github.com/pgjdbc/pgjdbc
Sejak pgjdbc 9.4-1202
itu secara otomatis menyimpan paket sisi server saat menggunakan PreparedStatement
.Catatan:pernyataan di-cache bahkan jika Anda close()
PreparedStatement
.Untuk mendapatkan persiapan sisi server, Anda perlu menjalankan kueri 5 kali (yang dapat dikonfigurasi melalui prepareThreshold
).
Saat ini, cache diimplementasikan per koneksi. Secara default pgjdbc menyimpan 256 (preparedStatementCacheQueries
) kueri dan hingga preparedStatementCacheSizeMiB
dari pertanyaan. Ini adalah pengaturan konservatif, jadi Anda mungkin ingin menyesuaikannya. Lihat dokumentasi
untuk deskripsi properti. Cache mencakup pernyataan yang diurai dan disiapkan server.
masalah github:https://github.com/pgjdbc/pgjdbc/pull/319
pgjdbc-ng
https://github.com/impossibl/pgjdbc-ng
Saya tidak menyukai pgjdbc-ng, namun sepertinya keduanya melakukan parsing (ukuran cache default adalah 250 kueri) dan persiapan server (ukuran cache default adalah 50 pertanyaan). Dukungan pernyataan yang disiapkan sisi server diluncurkan pada 24 Feb 2014, jadi jika Anda menggunakan versi yang agak baru, Anda bisa mendapatkan cache pernyataan.
Catatan:jika Anda secara tidak sengaja menggunakan kueri yang sangat panjang, Anda dapat menekan OutOfMemory
karena pgjdbc-ng tidak dapat menghapus entri berdasarkan jumlah byte yang disimpan.
Cache adalah per-koneksi, sehingga digunakan secara transparan bahkan jika Anda menutup pernyataan.
Saya tidak bisa mengatakan banyak tentang kinerja pgjdbc-ng meskipun sejak terakhir kali saya mencoba untuk melemparkan jmh itu gagal dengan pengecualian acak.
masalah github:https://github.com/impossibl/pgjdbc-ng/pull/ 69
Paket yang disiapkan server
PostgreSQL memiliki PREPARE
dan DEALLOCATE
perintah untuk mereferensikan pernyataan saat mengirim EXEC
di atas kawat. Ini mengoptimalkan dua hal:
- Saat menggunakan
PREPARE
d (dengan kata lain, yang disiapkan server), klien tidak perlu mengirim teks kueri berulang kali. Itu hanya mengirimkan nama kueri pendek dan nilai untuk variabel pengikat. - Sejak 9.2, database masih mencoba untuk merencanakan ulang beberapa eksekusi kueri pertama. Itu dilakukan untuk mencoba jika kueri membutuhkan banyak paket atau jika paket generik cukup baik. Akhirnya (segera jika kueri tidak memiliki parameter), database mungkin beralih ke paket umum .
- Sejak 12, ada pengaturan untuk memaksa SEMUA pernyataan yang disiapkan server dieksekusi dengan paket umum atau khusus:plan_cache_mode
=
auto | force_custom_plan | force_generic_plan
Dengan kata lain, PreparedStatement
mengoptimalkan penguraian kueri di sisi JDBC dan perencanaan kueri di sisi basis data.
Info lebih lanjut di sini:http://blog.endpoint .com/2014/04/custom-plans-prepared-statements-in.html
Pernyataan yang disiapkan dalam PL/pgSQL
Sesuai dokumentasi, PostgreSQL cache rencana untuk kueri yang digunakan dalam PL/pgSQL. Ini terjadi setelah beberapa eksekusi (3 atau 5, saya tidak ingat ambang batas yang tepat), jadi setelah Anda membuat prosedur tersimpan mungkin agak lambat, namun kemudian akan beralih ke paket yang di-cache (asalkan database setuju untuk menggunakan paket generik untuk kueri tertentu).
Dengan kata lain untuk mencapai "rencana eksekusi yang di-cache", Anda perlu menggunakan driver JDBC terbaru, atau Anda dapat membungkus semua kueri Anda ke dalam prosedur tersimpan. Panggilan ke prosedur akan direncanakan ulang pada setiap eksekusi, namun panggilan itu sendiri biasanya jauh lebih pendek daripada kueri yang menyusun prosedur.