Ekstensi kode pengujian Anda berikut ini informatif:
CREATE OR REPLACE FUNCTION test_multi_calls1(one integer)
RETURNS integer
AS $BODY$
BEGIN
RAISE NOTICE 'Immutable called with %', one;
RETURN one;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE;
CREATE OR REPLACE FUNCTION test_multi_calls2(one integer)
RETURNS integer
AS $BODY$
BEGIN
RAISE NOTICE 'Volatile called with %', one;
RETURN one;
END;
$BODY$ LANGUAGE plpgsql VOLATILE;
WITH data AS
(
SELECT 10 AS num
UNION ALL SELECT 10
UNION ALL SELECT 20
)
SELECT test_multi_calls1(num)
FROM data
where test_multi_calls2(40) = 40
and test_multi_calls1(30) = 30
KELUARAN:
NOTICE: Immutable called with 30
NOTICE: Volatile called with 40
NOTICE: Immutable called with 10
NOTICE: Volatile called with 40
NOTICE: Immutable called with 10
NOTICE: Volatile called with 40
NOTICE: Immutable called with 20
Di sini kita dapat melihat bahwa sementara di daftar pilih, fungsi yang tidak dapat diubah dipanggil beberapa kali, di klausa where dipanggil sekali, sedangkan volatil disebut tiga kali.
Yang penting bukan PostgreSQL hanya akan memanggil STABLE
atau IMMUTABLE
berfungsi sekali dengan data yang sama - contoh Anda dengan jelas menunjukkan bahwa ini bukan masalahnya - hanya saja mungkin menyebutnya hanya sekali. Atau mungkin akan memanggilnya dua kali ketika harus memanggil versi volatil sebanyak 50 kali, dan seterusnya.
Ada berbagai cara di mana stabilitas dan kekekalan dapat dimanfaatkan, dengan biaya dan manfaat yang berbeda. Untuk menyediakan jenis penghematan yang Anda sarankan untuk dibuat dengan daftar-pilih, ia harus men-cache hasilnya, dan kemudian mencari setiap argumen (atau daftar argumen) dalam cache ini sebelum mengembalikan hasil yang di-cache atau memanggil fungsi pada cache -merindukan. Ini akan lebih mahal daripada memanggil fungsi Anda, bahkan dalam kasus di mana ada persentase cache-hit yang tinggi (mungkin ada 0% cache hit yang berarti "pengoptimalan" ini melakukan pekerjaan ekstra tanpa keuntungan sama sekali). Itu mungkin hanya menyimpan parameter dan hasil terakhir, tetapi sekali lagi itu bisa sama sekali tidak berguna.
Ini terutama mengingat bahwa fungsi yang stabil dan tidak dapat diubah seringkali merupakan fungsi yang paling ringan.
Namun, dengan klausa where, kekekalan test_multi_calls1
memungkinkan PostgreSQL untuk benar-benar merestrukturisasi kueri dari arti sederhana dari SQL yang diberikan:
Ke paket kueri yang sama sekali berbeda:
Ini adalah jenis penggunaan yang dibuat PostgreSQL dari STABLE dan IMMUTABLE - bukan caching hasil, tetapi penulisan ulang kueri menjadi kueri berbeda yang lebih efisien tetapi memberikan hasil yang sama.
Perhatikan juga bahwa test_multi_calls1(30) dipanggil sebelum test_multi_calls2(40) tidak peduli urutan kemunculannya di klausa where. Ini berarti bahwa jika panggilan pertama tidak menghasilkan baris yang dikembalikan (ganti = 30
dengan = 31
untuk menguji) maka fungsi volatil tidak akan dipanggil sama sekali - lagi-lagi terlepas dari sisi mana and
.
Jenis penulisan ulang khusus ini bergantung pada kekekalan atau stabilitas. Dengan where test_multi_calls1(30) != num
penulisan ulang kueri akan terjadi untuk yang tidak dapat diubah tetapi tidak hanya untuk fungsi yang stabil. Dengan where test_multi_calls1(num) != 30
itu tidak akan terjadi sama sekali (beberapa panggilan) meskipun ada kemungkinan pengoptimalan lain:
Ekspresi yang hanya berisi fungsi STABLE dan IMMUTABLE dapat digunakan dengan pemindaian indeks. Ekspresi yang mengandung fungsi VOLATILE tidak bisa. Jumlah panggilan mungkin atau mungkin tidak berkurang, tetapi yang lebih penting, hasil panggilan akan digunakan dengan cara yang jauh lebih efisien di sisa kueri (hanya benar-benar penting pada tabel besar, tetapi kemudian dapat membuat perbedaan).
Secara keseluruhan, jangan pikirkan kategori volatilitas dalam hal memoisasi, melainkan dalam hal memberikan peluang perencana kueri PostgreSQL untuk merestrukturisasi seluruh kueri dengan cara yang setara secara logis (hasil yang sama) tetapi jauh lebih efisien.