Pertanyaan pemula:
Saya memiliki fungsi yang mahal f(x, y)
pada dua kolom x dan y dalam tabel database saya.
Saya ingin mengeksekusi kueri yang memberi saya hasil fungsi sebagai kolom dan menempatkan kendala di atasnya, sesuatu seperti
SELECT *, f(x, y) AS func FROM table_name WHERE func < 10;
Namun ini tidak berhasil, jadi saya harus menulis sesuatu seperti
SELECT *, f(x, y) AS func FROM table_name WHERE f(x, y) < 10;
Apakah ini akan menjalankan fungsi mahal dua kali? Apa cara terbaik untuk melakukan ini?
postgresql
postgresql-9.4
Jack Black
sumber
sumber
STABLE
/IMMUTABLE
atauVOLATILE
?Jawaban:
Mari kita membuat fungsi yang memiliki efek samping sehingga kita dapat melihat berapa kali dieksekusi:
Dan sebut ini seperti yang Anda lakukan:
Seperti yang Anda lihat, fungsi dipanggil setidaknya sekali (dari
WHERE
klausa), dan ketika kondisinya benar, sekali lagi untuk menghasilkan output.Untuk menghindari eksekusi kedua, Anda dapat melakukan apa yang disarankan Edgar - yaitu membungkus kueri dan memfilter set hasil:
Untuk lebih lanjut memeriksa bagaimana ini bekerja, seseorang dapat pergi ke
pg_stat_user_functions
dan memeriksa dicalls
sana (diberikantrack_functions
diatur ke 'semua).Mari kita coba dengan sesuatu yang tidak memiliki efek samping:
simple()
sebenarnya terlalu sederhana sehingga dapat diuraikan , oleh karena itu tidak muncul dalam tampilan. Mari kita membuatnya menjadi tidak dapat ditiru:Seperti yang terlihat, gambarnya sama dengan atau tanpa efek samping.
Mengubah
other_one()
keIMMUTABLE
perubahan perilaku (mungkin mengejutkan) untuk lebih buruk, karena akan disebut 13 kali di kedua query.sumber
Coba panggil lagi:
sumber