La seguente estensione del codice di prova è informativo:
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
USCITA:
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
Qui possiamo vedere che, mentre nella select-list la funzione immutabile è stato chiamato più volte, in la clausola where è stata chiamata una volta, mentre il volatile è stato chiamato tre volte.
La cosa importante non è che PostgreSQL chiamerà solo una funzione STABLE
o IMMUTABLE
una volta con gli stessi dati - il tuo esempio mostra chiaramente che questo non è il caso - è che possa chiamarla soltanto una volta. O forse lo chiamerà due volte quando dovrebbe chiamare una versione volatile 50 volte, e così via.
Esistono diversi modi in cui è possibile sfruttare la stabilità e l'immutabilità con costi e vantaggi diversi. Per fornire il tipo di salvataggio che stai suggerendo dovrebbe fare con select-lists dovrebbe mettere in cache i risultati, e quindi cercare ogni argomento (o elenco di argomenti) in questa cache prima di restituire il risultato memorizzato nella cache o chiamare la funzione su una cache -Perdere. Questo sarebbe più costoso che chiamare la tua funzione, anche nel caso in cui ci fosse un'alta percentuale di hit della cache (potrebbero esserci hit della cache pari allo 0%, il che significa che questa "ottimizzazione" ha fatto un lavoro extra senza alcun guadagno). Potrebbe memorizzare solo l'ultimo parametro e il risultato, ma di nuovo potrebbe essere completamente inutile.
Ciò è particolarmente vero considerando che le funzioni stabili e immutabili sono spesso le funzioni più leggere.
Con la clausola where tuttavia, l'immutabilità test_multi_calls1
permette PostgreSQL effettivamente ristrutturare le query dal significato piana del SQL proposta:
Per ogni riga calcolare test_multi_calls1 (30) e se il risultato è pari a 30, continuare l'elaborazione della riga in questione
per un diverso piano di query interamente:
Calcolare test_multi_calls1 (30) e se è uguale a 30 poi continuare con la query altrimenti restituisce una riga di zero set di risultati, senza ad ulteriori calcoli
Questo è il tipo di utilizzo che PostgreSQL rende di stabili e IMMUTABILE - non la memorizzazione nella cache dei risultati, ma la riscrittura delle query in query diverse che sono più efficienti ma danno gli stessi risultati.
Nota anche che test_multi_calls1 (30) viene chiamato prima di test_multi_calls2 (40) indipendentemente dall'ordine in cui appaiono nella clausola where. Ciò significa che se la prima chiamata non restituisce alcuna riga (sostituire = 30
con = 31
per il test), la funzione volatile non verrà richiamata affatto, sempre indipendentemente da quale sia il lato dello and
.
Questo particolare tipo di riscrittura dipende dall'immutabilità o dalla stabilità. Con where test_multi_calls1(30) != num
la riscrittura delle query avverrà per funzioni immutabili ma non per quelle semplicemente stabili. Con where test_multi_calls1(num) != 30
non avverrà affatto (chiamate multiple) anche se ci sono altre ottimizzazioni possibili:
Le espressioni contenenti solo funzioni STABILE e IMMUTABILE possono essere utilizzate con le scansioni di indice. Le espressioni che contengono le funzioni VOLATILI non possono. Il numero di chiamate può o non può diminuire, ma molto più importante il risultato delle chiamate verrà quindi utilizzato in un modo molto più efficiente nel resto della query (conta solo sui tavoli grandi, ma poi può fare un grande differenza).
In generale, non pensare alle categorie di volatilità in termini di memoria, ma piuttosto in termini di opportunità di pianificazione di query di PostgreSQL per ristrutturare intere query in modi che sono logicamente equivalenti (stessi risultati) ma molto più efficienti.
Cose interessanti –