Performance delle funzioni


46

Provenendo da un background MySQL, in cui le prestazioni della procedura memorizzata (articolo precedente) e l' usabilità sono discutibili, sto valutando PostgreSQL per un nuovo prodotto per la mia azienda.

Una delle cose che vorrei fare è spostare parte della logica dell'applicazione in stored procedure, quindi sto qui chiedendo DO e DON (best practice) sull'uso delle funzioni in PostgreSQL (9.0), in particolare per quanto riguarda le insidie ​​delle prestazioni.


vuoi dire che non vuoi che le risposte menzionino qualcosa di non correlato alle prestazioni?
Jack Douglas,

Chris Travers blog molto sui vantaggi dell'utilizzo di stored procedure, ad esempio qui: ledgersmbdev.blogspot.de/2012/07/… e qui: ledgersmbdev.blogspot.de/2012/07/… basta sfogliare il suo blog, ci sono molti articoli interessanti su questo argomento.
a_horse_with_no_name

Risposte:


51

A rigor di termini, il termine "stored procedure" indica le procedure SQL in Postgres, introdotte con Postgres 11.

Ci sono anche funzioni che fanno quasi ma non esattamente la stessa cosa e che ci sono state fin dall'inizio.

Le funzioni con LANGUAGE sqlsono fondamentalmente solo file batch con semplici comandi SQL in un wrapper di funzioni (e quindi atomici, sempre eseguiti all'interno di una singola transazione) che accettano parametri. Tutte le istruzioni in una funzione SQL vengono pianificate contemporaneamente , il che è leggermente diverso dall'esecuzione di un'istruzione dopo l'altra e può influire sull'ordine in cui vengono eseguiti i blocchi.

Per di più, il linguaggio più maturo è PL / pgSQL ( LANGUAGE plpgsql). Funziona bene ed è stato migliorato con ogni versione nell'ultimo decennio, ma serve come colla per i comandi SQL. Non è pensato per calcoli pesanti (tranne che con i comandi SQL).

Le funzioni PL / pgSQL eseguono query come istruzioni preparate . Il riutilizzo dei piani di query memorizzati nella cache elimina alcune spese generali di pianificazione e le rende un po 'più veloci delle equivalenti istruzioni SQL, il che può essere un effetto evidente a seconda delle circostanze. Potrebbe anche avere effetti collaterali come in questa domanda correlata:

Ciò comporta i vantaggi e gli svantaggi delle dichiarazioni preparate, come discusso nel manuale . Per query nelle tabelle con distribuzione irregolare dati e parametri variabili SQL dinamico con EXECUTEpuò eseguire meglio quando il guadagno da un piano di esecuzione ottimizzata per il dato parametro (s) supera il costo di ri-pianificazione.

Poiché i piani di esecuzione generici di Postgres 9.2 sono ancora memorizzati nella cache per la sessione ma, citando il manuale :

Ciò si verifica immediatamente per le istruzioni preparate senza parametri; in caso contrario, si verifica solo dopo che cinque o più esecuzioni hanno prodotto piani la cui media dei costi stimati (incluso il sovraccarico di pianificazione) è più costosa della stima dei costi del piano generico.

Otteniamo il meglio da entrambi i mondi per la maggior parte del tempo (meno alcune spese generali aggiunte) senza (ab) utilizzare EXECUTE. Dettagli in Novità di PostgreSQL 9.2 del Wiki PostgreSQL .

Postgres 12 introduce la variabile serverplan_cache_mode aggiuntiva per forzare piani generici o personalizzati. Per casi speciali, usare con cura.

Puoi vincere alla grande con le funzioni lato server che impediscono ulteriori round trip al server di database dalla tua applicazione. Chiedi al server di eseguire il più possibile in una volta sola e restituisce solo un risultato ben definito.

Evitare l'annidamento di funzioni complesse, in particolare le funzioni di tabella ( RETURNING SETOF recordo TABLE (...)). Le funzioni sono scatole nere che si pongono come barriere di ottimizzazione per il planner delle query. Sono ottimizzati separatamente, non nel contesto della query esterna, il che rende la pianificazione più semplice, ma può risultare in piani tutt'altro che perfetti. Inoltre, le dimensioni dei costi e dei risultati delle funzioni non possono essere previste in modo affidabile.

L' eccezione a questa regola sono le semplici funzioni SQL ( LANGUAGE sql), che possono essere "incorporate" - se vengono soddisfatte alcune condizioni preliminari . Maggiori informazioni su come funziona il planner delle query in questa presentazione di Neil Conway (cose avanzate).

In PostgreSQL una funzione viene sempre eseguita automaticamente all'interno di una singola transazione . Tutto ha successo o niente. Se si verifica un'eccezione, viene eseguito il rollback di tutto. Ma c'è una gestione degli errori ...

Questo è anche il motivo per cui le funzioni non sono esattamente "stored procedure" (anche se quel termine viene usato talvolta, in modo fuorviante). Alcuni comandi piace VACUUM, CREATE INDEX CONCURRENTLYo CREATE DATABASEnon possono essere eseguiti all'interno di un blocco di transazione, quindi non sono consentiti nelle funzioni. (Nemmeno nelle procedure SQL, a partire da Postgres 11. Che potrebbe essere aggiunto in seguito.)

Ho scritto migliaia di funzioni plpgsql nel corso degli anni.


2
@nhahtdh: "transazione automatica" non è un termine tecnico. Era solo un modo poco elegante di dire ... quello che sta dicendo ora dopo il mio chiarimento. Nessuna transazione autonoma. "autonomo" sembra essere una parola simile.
Erwin Brandstetter,

4
Le tue risposte compilate da qui e SO potrebbero essere un epico manuale di buone pratiche PostGreSQL.
Davos,

10

Alcuni DO:

  • Utilizzare SQL come linguaggio delle funzioni quando possibile, poiché PG può incorporare le istruzioni
  • Usa IMMUTABLE / STABLE / VOLATILE correttamente, poiché PG può memorizzare nella cache i risultati se è immutabile o stabile
  • Utilizzare STRICT correttamente, poiché PG può restituire null solo se qualsiasi input è null invece di eseguire la funzione
  • Considerare PL / V8 quando non è possibile utilizzare SQL come linguaggio delle funzioni. È più veloce di PL / pgSQL in alcuni test non scientifici che ho eseguito
  • Utilizzare ASCOLTA / NOTIFICA per processi a esecuzione più lunga che possono verificarsi fuori transazione
  • Considera di utilizzare le funzioni per implementare l'impaginazione poiché l'impaginazione basata su chiave può essere più veloce dell'impaginazione basata su LIMIT
  • Assicurati di testare le tue unità

È la prima volta che vedo l'affermazione che PL / V8 è più veloce di PL / pgSQL. Hai delle cifre (pubblicate) a supporto di ciò?
a_horse_with_no_name

@a_horse_with_no_name no, non lo so. Come ho detto, ho fatto alcuni test non scientifici. Erano principalmente logici, non di accesso ai dati. Proverò a fare alcuni test ripetibili su Natale e ripubblicare qui.
Neil McGuigan,

@a_horse_with_no_name ecco un esempio rapido per FizzBuzz plv8 vs plpgsql: blog.databasepatterns.com/2014/08/plv8-vs-plpgsql.html
Neil McGuigan

8

In generale, spostare la logica dell'applicazione nel database significa che è più veloce, dopotutto verrà eseguito più vicino ai dati.

Credo (ma non sono sicuro al 100%) che le funzioni del linguaggio SQL siano più veloci di quelle che usano altre lingue perché non richiedono il cambio di contesto. Il rovescio della medaglia è che non è consentita alcuna logica procedurale.

PL / pgSQL è il più maturo e completo di funzionalità dei linguaggi incorporati, ma per le prestazioni, è possibile utilizzare C (anche se andrà a beneficio solo delle funzioni ad alta intensità computazionale)


7

Puoi fare alcune cose molto interessanti usando le funzioni definite dall'utente (UDF) in postgresql. Ad esempio, ci sono dozzine di lingue possibili che puoi usare. Il costruito in pl / sql e pl / pgsql sono entrambi capaci e affidabili e usano un metodo sandbox per impedire agli utenti di fare qualcosa di terribilmente pericoloso. Gli UDF scritti in C offrono il massimo in termini di potenza e prestazioni, poiché funzionano nello stesso contesto del database stesso. Tuttavia, è come giocare con il fuoco, perché anche piccoli errori possono causare enormi problemi, con arresti anomali del back-end o danneggiamento dei dati. I linguaggi pl personalizzati, come pl / R, pl / ruby, pl / perl e così via, offrono la possibilità di scrivere sia il database che i livelli app nelle stesse lingue. Questo può essere utile, poiché significa che non è necessario insegnare a un programmatore perl java o pl / pgsql ecc per scrivere un UDF.

Infine, esiste il linguaggio pl / proxy . Questo linguaggio UDF ti consente di eseguire la tua applicazione su dozzine o più server postgresql back-end a fini di ridimensionamento. È stato sviluppato dalla brava gente di Skype e sostanzialmente consente la soluzione di ridimensionamento orizzontale di un uomo povero. È sorprendentemente facile anche scrivere.

Ora, per quanto riguarda il problema delle prestazioni. Questa è una zona grigia. Stai scrivendo un'app per una persona? O per 1.000? o per 10.000.000? Il modo in cui costruisci la tua app e usi gli UDF dipenderà MOLTO da come stai cercando di ridimensionare. Se stai scrivendo per migliaia e migliaia di utenti, la cosa principale che vuoi fare è ridurre il carico sul db il più possibile. Gli UDF che riducono la quantità di dati spostati all'esterno e nel database contribuiranno a ridurre il carico di I / O. Tuttavia, se iniziano ad aumentare il carico della CPU, potrebbero essere un problema. In generale, ridurre il carico di I / O è la prima priorità e assicurarsi che gli UDF siano efficienti in modo da non sovraccaricare le CPU.

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.