Dichiarare la volatilità delle funzioni IMMUTABILE può danneggiare le prestazioni?


9

Le funzioni di Postgres sono dichiarate con classificazione di volatilità VOLATILE, STABLEoIMMUTABLE . Il progetto è noto per essere molto severo con queste etichette per le funzioni integrate. E con una buona ragione. Esempio di spicco: gli indici di espressione consentono solo IMMUTABLEfunzioni e queste devono essere veramente immutabili per evitare risultati errati.

Le funzioni definite dall'utente sono ancora libere di essere dichiarate quando il proprietario sceglie. Il manuale consiglia:

Per i migliori risultati di ottimizzazione, è necessario etichettare le funzioni con la categoria di volatilità più rigorosa valida per esse.

... e aggiunge un ampio elenco di cose che possono andare storte con un'etichetta di volatilità errata.

Tuttavia, ci sono casi in cui falsificare l'immutabilità ha senso. Soprattutto quando sai che la funzione è, infatti, immutabile nel tuo ambito. Esempio:

Tutte le possibili implicazioni sull'integrità dei dati a parte , qual è l'effetto sulle prestazioni? Si potrebbe supporre che la dichiarazione di una funzione IMMUTABLEpossa essere vantaggiosa solo per le prestazioni . È così?

La dichiarazione di volatilità delle funzioni può IMMUTABLE danneggiare le prestazioni?

Supponiamo che l'attuale Postgres 10 lo restringa, ma tutte le versioni recenti sono interessanti.


1
Come nota a margine, l'intero "veramente immutabile" sugli indici di espressione è una vera pita. È un'interfaccia utente orribile. Dovremmo essere in grado in FORCEentrambi i modi. Il 100% dei DBA PostgreSQL con esperienza mentono per aggirare quell'interfaccia utente con funzioni wrapper. Almeno con FORCE, non avremmo bisogno di involucri e non dovremmo mentire sulla volatilità dichiarata.
Evan Carroll,

1
Presumo FORCEche gli indici di espressione debbano accettare funzioni non immutabili (contrassegnandoli come potenziale punto di errore). Sì, sembrerebbe una soluzione più elegante dei wrapper di funzioni immutabili.
Erwin Brandstetter,

Non so quasi nulla di PostGres ma la volatilità non è volatile ridondante? Cosa significa? Seriamente non ti aspetti che sia affidabile, perché è pazzo ?
Anthony,

@Anthony: ho chiarito un po 'di più. Seguire il collegamento al manuale per i dettagli.
Erwin Brandstetter,

Risposte:


7

Sì, può danneggiare le prestazioni.

Le funzioni SQL semplici possono essere "incorporate" nella query chiamante. Citando il Wiki di Postgres :

Le funzioni SQL (ad es. LANGUAGE SQL) Avranno, in determinate condizioni, i loro corpi funzione incorporati nella query chiamante anziché essere richiamati direttamente. Ciò può comportare vantaggi sostanziali in termini di prestazioni poiché il corpo della funzione viene esposto al pianificatore della query chiamante, che può applicare ottimizzazioni come la piegatura costante, il pushdown di qualità e così via.

Enorme enfasi sulla mia.

Per imporre la correttezza, ci sono una serie di condizioni preliminari. Uno di questi :

se la funzione è dichiarata IMMUTABLE, l'espressione non deve invocare alcuna funzione o operatore non immutabile

Significato, le funzioni SQL che utilizzano qualsiasi funzione non immutabile ma che sono ancora dichiarate IMMTUTABLEsono escluse da questa ottimizzazione. Innescato da queste risposte correlate su SO, ho eseguito test approfonditi:

Fondamentalmente confrontando queste due varianti di una semplice funzione SQL (mappando le date a un integer, ignorando l'anno che non ha importanza per lo scopo):

CREATE FUNCTION f_mmdd_tc_s(date) RETURNS int LANGUAGE sql STABLE    AS
$$SELECT to_char($1, 'MMDD')::int$$;

CREATE FUNCTION f_mmdd_tc_i(date) RETURNS int LANGUAGE sql IMMUTABLE AS
$$SELECT to_char($1, 'MMDD')::int$$;  -- cannot be inlined!

La funzione Postgres to_char()è solo STABLE, non IMMUTABLE(tutte le sue istanze sovraccaricate - per ragioni che esulano dallo scopo di questa risposta ). Quindi il secondo è falso IMMUTABLEe risulta essere 5 volte più lento in un semplice test:

db <> violino qui

Questo esempio specifico può essere sostituito con l'equivalente:

CREATE FUNCTION f_mmdd(date) RETURNS int LANGUAGE sql IMMUTABLE AS
$$SELECT (EXTRACT(month FROM $1) * 100 + EXTRACT(day FROM $1))::int$$;

Sarebbe sembrare più costoso con due chiamate di funzione e altri calcoli. Ma l' IMMUTABLEetichetta è vero (più, la funzione utilizzata è più veloce e costringere texta integerè più costoso, troppo).

2 volte più veloce della variante più veloce sopra (10 volte più veloce del più lento). Il punto è: usa le IMMUTABLEfunzioni ove possibile , quindi non devi "imbrogliare" per cominciare.


Risultati fantastici! Avere un seguito immediato: dba.stackexchange.com/q/212198/2639
Evan Carroll

Sai cosa penso di aver perso qui, che non sapevo. Anche questo STABLEè in linea. Ho pensato che l'ottimizzatore avrebbe IMMUTABLEfunzionato solo online .
Evan Carroll,

VOLATILEaltrettanto bene.
Erwin Brandstetter,

Il wiki dice che la funzione è dichiarata STABLE o IMMUTABLE wiki.postgresql.org/wiki/Inlining_of_SQL_functions
Evan Carroll

.. in "Condizioni di allineamento per le funzioni di tabella ". Non per funzioni scalari. L'ho dimostrato nel violino: dbfiddle.uk/…
Erwin Brandstetter il
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.