답변:
몇 번 실행되는지 볼 수 있도록 부작용이있는 함수를 만들어 봅시다 :
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
절 에서 한 번 이상 호출되고 조건이 true이면 다시 한 번 출력을 생성합니다.
두 번째 실행을 피하기 위해 Edgar가 제안한대로 , 즉 쿼리를 래핑하고 결과 집합을 필터링 할 수 있습니다.
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
것이 'all').
부작용이없는 것으로 시도해 보자.
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 번 호출 될 것이다 변경 악화로 동작을 (어쩌면 당연한).
다시 불러보십시오.
SELECT
*
FROM (
SELECT
*,
f(x, y) AS func
FROM table_name
) a
WHERE a.func < 10;
STABLE
/IMMUTABLE
나VOLATILE
?