PostgreSQL Antipatterns: combattiamo contro orde di "morti viventi"

Le caratteristiche del funzionamento dei meccanismi interni di PostgreSQL gli consentono di essere molto veloce in alcune situazioni e "non molto" in altre. Oggi ci concentreremo su un classico esempio di conflitto tra il modo in cui funziona un DBMS e ciò che fa con esso lo sviluppatore — UPDATE vs principi MVCC.

Brevemente il racconto di un ottimo articolo:

Quando una riga viene modificata con il comando UPDATE, vengono effettivamente eseguite due operazioni: DELETE e INSERT. In versione corrente della riga viene impostato xmax, uguale al numero della transazione che ha eseguito l'UPDATE. Viene quindi creata nuova versione la stessa riga; il valore xmin di essa coincide con il valore xmax della versione precedente.

Dopo un certo tempo, al termine di questa transazione, la vecchia o nuova versione, a seconda di COMMIT/ROLLBACK, verranno riconosciute "morte" (dead tuples) durante il passaggio VACUUM attraverso la tabella e ripulite.

PostgreSQL Antipatterns: combattiamo contro orde di "morti viventi"

Ma questo non accadrà immediatamente, mentre i problemi con i "morti" possono insorgere molto rapidamente — durante aggiornamenti ripetuti o massivi di record in una grande tabella, e poco dopo ci si può trovare nella situazione in cui neanche VACUUM potrà aiutare..

#1: I Like To Move It

Supponiamo che il tuo metodo basato sulla logica di business stia funzionando, e all'improvviso si rende conto che dovrebbe aggiornare il campo X in un certo record:

UPDATE tbl SET X =  WHERE pk = $1;

Poi, nel corso dell'esecuzione, scopre che dovrebbe aggiornare anche il campo Y:

UPDATE tbl SET Y =  WHERE pk = $1;

… e poi anche Z — perché risparmiare?

UPDATE tbl SET Z =  WHERE pk = $1;

Quante versioni di questo record abbiamo ora nel database? Ah, 4 pezzi! Di cui una attuale, mentre 3 dovranno essere ripuliti da te con [auto]VACUUM.

Non farlo! Usa l'aggiornamento di tutti i campi in un'unica query — quasi sempre la logica di funzionamento del metodo può essere cambiata in questo modo:

UPDATE tbl SET X = , Y = , Z =  WHERE pk = $1;

#2: Use IS DISTINCT FROM, Luke!

Quindi, ti sei davvero deciso a aggiornare molti record nella tabella (durante l'esecuzione di uno script o un convertitore, ad esempio). E nello script appare qualcosa del tipo:

UPDATE tbl SET X =  WHERE pk BETWEEN $1 AND $2;

In una forma simile, la query si incontra abbastanza spesso e quasi sempre non per riempire un nuovo campo vuoto, ma per correggere alcuni errori nei dati. In questo caso, la correttezza dei dati già esistenti non viene affatto considerata — a sproposito! Vale a dire che il record viene riscritto, anche se c'era esattamente ciò che si desiderava — e perché? Correggiamo:

UPDATE tbl SET X =  WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM ;

Molti non sono a conoscenza dell'esistenza di questo straordinario operatore, quindi ecco una guida su IS DISTINCT FROM e altri operatori logici per aiutarti:
PostgreSQL Antipatterns: combattiamo contro orde di "morti viventi"
… e un po' sulle operazioni con espressioni ROW()-complesse:
PostgreSQL Antipatterns: combattiamo contro orde di "morti viventi"

#3: А я милого узнаю по… блокировке

Vengono avviati due processi paralleli identici, ognuno dei quali cerca di segnare il record come "in lavorazione":

UPDATE tbl SET processing = TRUE WHERE pk = $1;

Anche se questi processi svolgono effettivamente cose indipendenti l'uno dall'altro, all'interno di un unico ID, su questa richiesta il secondo client "si bloccherà" fino a quando non termina la prima transazione.

Soluzione nº1: il problema è stato ridotto al precedente

Semplicemente aggiungiamo di nuovo IS DISTINCT FROM:

UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;

In questo modo, la seconda richiesta semplicemente non apporterà modifiche nel database, dove già "è tutto a posto" — quindi non si verificherà alcun blocco. In seguito, il fatto che il record "non si trovi" verrà già gestito nell'algoritmo applicativo.

Soluzione nº2: blocchi advisory

Un grande tema per un articolo a parte, dove si può leggere su i metodi di applicazione e i "problemi" dei blocchi raccomandati.

Soluzione nº3: senza [d]ubbio delle chiamate

Ecco, esattamente, dovrebbe verificarsi la tua lavorazione simultanea dello stesso record? Или вы все-таки накосячили с алгоритмами вызовов бизнес-логики со стороны клиента, например? А если подумать?..

Fonte: habr.com

Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server 🔥 Acquista hosting affidabile per siti web con protezione DDoS, VPS VDS server | ProHoster