आइए एक फ़ंक्शन बनाएं जिसका साइड इफेक्ट हो ताकि हम यह देख सकें कि इसे कितनी बार निष्पादित किया गया है:
CREATE OR REPLACE FUNCTION test.this_here(val integer)
RETURNS numeric
LANGUAGE plpgsql
AS $function$
BEGIN
RAISE WARNING 'I am called with %', val;
RETURN sqrt(val);
END;
$function$;
और फिर इस तरह कॉल करें जैसे आप करते हैं:
SELECT this_here(i) FROM generate_series(1,10) AS t(i) WHERE this_here(i) < 2;
WARNING: I am called with 1
WARNING: I am called with 1
WARNING: I am called with 2
WARNING: I am called with 2
WARNING: I am called with 3
WARNING: I am called with 3
WARNING: I am called with 4
WARNING: I am called with 5
WARNING: I am called with 6
WARNING: I am called with 7
WARNING: I am called with 8
WARNING: I am called with 9
WARNING: I am called with 10
this_here
──────────────────
1
1.4142135623731
1.73205080756888
(3 rows)
जैसा कि आप देखते हैं, फ़ंक्शन को कम से कम एक बार ( WHERE
खंड से) कहा जाता है , और जब स्थिति सच होती है, तो एक बार फिर से उत्पादन करने के लिए।
दूसरे निष्पादन से बचने के लिए, आप वही कर सकते हैं जो एडगर सुझाता है - अर्थात् क्वेरी को लपेटें और परिणाम सेट को फ़िल्टर करें:
SELECT *
FROM (SELECT this_here(i) AS val FROM generate_series(1,10) AS t(i)) x
WHERE x.val < 2;
WARNING: I am called with 1
... every value only once ...
WARNING: I am called with 10
यह जांचने के लिए कि यह कैसे काम करता है, कोई भी जा सकता है pg_stat_user_functions
और calls
वहां जांच कर सकता है (दिया गया track_functions
है, सभी के लिए सेट है)।
आइए ऐसी किसी चीज़ के साथ कोशिश करें जिसका कोई साइड इफ़ेक्ट न हो:
CREATE OR REPLACE FUNCTION test.simple(val numeric)
RETURNS numeric
LANGUAGE sql
AS $function$
SELECT sqrt(val);
$function$;
SELECT simple(i) AS v
FROM generate_series(1,10) AS t(i)
WHERE simple(i) < 2;
-- output omitted
SELECT * FROM pg_stat_user_functions WHERE funcname = 'simple';
-- 0 rows
simple()
वास्तव में बहुत सरल है , इसलिए इसे इनलेट किया जा सकता है , इसलिए यह दृश्य में दिखाई नहीं देता है। आइए इसे अप्राप्य बनाएं:
CREATE OR REPLACE FUNCTION test.other_one(val numeric)
RETURNS numeric
LANGUAGE sql
AS $function$
SELECT 1; -- to prevent inlining
SELECT sqrt(val);
$function$;
SELECT other_one(i) AS v
FROM generate_series(1,10) AS t(i)
WHERE other_one(i) < 2;
SELECT * FROM pg_stat_user_functions ;
funcid │ schemaname │ funcname │ calls │ total_time │ self_time
────────┼────────────┼───────────┼───────┼────────────┼───────────
124311 │ test │ other_one │ 13 │ 0.218 │ 0.218
SELECT *
FROM (SELECT other_one(i) AS v FROM generate_series(1,10) AS t(i)) x
WHERE v < 2;
SELECT * FROM pg_stat_user_functions ;
funcid │ schemaname │ funcname │ calls │ total_time │ self_time
────────┼────────────┼───────────┼───────┼────────────┼───────────
124311 │ test │ other_one │ 23 │ 0.293 │ 0.293
जैसा कि दिखता है, चित्र साइड इफेक्ट्स के साथ या बिना समान है।
बदलने other_one()
के लिए IMMUTABLE
, परिवर्तन व्यवहार (शायद आश्चर्य की बात) बदतर करने के लिए, क्योंकि यह दोनों प्रश्नों में 13 बार बुलाया जाएगा।
STABLE
/IMMUTABLE
याVOLATILE
?