Koncepcyjnie jest leniwy:
Podobnie jak wyrażenie CASE, zlewają ocenia jedynie argumenty, które są potrzebne do ustalenia wyniku; to znaczy, argumenty z prawej strony pierwszego nie-zerowego argumentu nie są oceniane.
https://www.postgresql.org/docs/9.6/static/functions-conditional.html
Jednakże, jeśli wyrażenie w prawo nie jest lotny to powinno robić żadnej różnicy, czy to leniwy lub nie, więc w takim przypadku byłoby to dopuszczalne dla projektanta zapytań niecierpliwością ocenić prawy argument, jeśli był stabilny lub niezmienny, jeśli wydawało się to sensowną optymalizacją.
Oczywistym jest, że sprawa z SELECT COALESCE(a, b) FROM table
będzie prawdopodobnie odzyskać a
i b
pól wszystkich wierszy zamiast pobierania a
a następnie pobierania b
w razie potrzeby.
Jedynym sposobem uzyskania widocznego efektu jest napisanie funkcji niestabilnej i celowo błędnie oznaczono ją jako stable
lub immutable
. Byłoby wówczas możliwe oszacowanie, czy po prawej stronie coalesce
, gdzie lewa ręka nie była pusta. (Oczywiście byłaby możliwa funkcja, która naprawdę byłaby stabilna, ale gdyby była stabilna, nie miałaby skutków ubocznych, a gdyby nie miała efektów ubocznych, to czy byłaby, czy nie, nie byłaby obserwowalna).
Dane:
CREATE OR REPLACE FUNCTION immutable_func(arg integer)
RETURNS integer
AS $BODY$
BEGIN
RAISE NOTICE 'Immutable function called with %', arg;
RETURN arg;
END;
$BODY$ LANGUAGE plpgsql IMMUTABLE;
WITH data AS
(
SELECT 10 AS num
UNION ALL SELECT 5
UNION ALL SELECT 20
)
select coalesce(num, immutable_func(2))
from data
Planista wie, że będzie miał taki sam wynik dla immutable_func(2)
dla każdego wiersza i wzywa go jeden raz dla całego zapytania, dając nam wiadomość Immutable function called with 2
. Tak więc został on faktycznie oceniony, mimo że nie mieści się w zasadzie "argumenty z prawej strony pierwszego nie-zerowego argumentu nie są oceniane". Opłatą jest to, że w (rozsądnym do spodziewanego) przypadku wielokrotnego null num
nadal będzie działać tylko jeden raz.
Jest to sprzeczne z literą udokumentowanego zachowania, ponieważ powiedzieliśmy, że taka optymalizacja jest ważna. Jeśli spowodowałoby to problem, błąd oznaczałby funkcję oznaczoną jako IMMUTABLE
, a nie w gorącej ocenie.
Może być również w części. Z wartością SELECT COALESCE(a, Some_Func(b)) FROM table
nie będzie on chętnie oceniać wartości Some_Func(b)
, ale będzie mógł pobrać b
, aby móc to zrobić.
Za każdym razem, gdy ma to wpływ na zaobserwowane zachowanie (nieuczestniczące), przestrzegana jest zasada.
Dobre pytanie. Powiedziałbym: sprawdź plan. – wildplasser