PostgreSQL Antipattern: combattere orde di "morti"

Le peculiarità dei meccanismi interni di PostgreSQL gli permettono di essere molto veloce in alcune situazioni e “poco veloce” in altre. Oggi ci concentreremo su un classico esempio di conflitto tra il funzionamento di un DBMS e ciò che ne fa lo sviluppatore: AGGIORNAMENTO vs principi MVCC.

Breve storia da ottimo articolo:

Quando una riga viene modificata da un comando UPDATE, vengono effettivamente eseguite due operazioni: DELETE e INSERT. IN versione corrente della stringa xmax è impostato uguale al numero della transazione che ha eseguito l'AGGIORNAMENTO. Quindi viene creato nuova versione la stessa linea; il suo valore xmin coincide con il valore xmax della versione precedente.

Qualche tempo dopo il completamento di questa transazione, la versione vecchia o nuova, a seconda COMMIT/ROOLBACK, verrà riconosciuto "morto" (tuple morte) al passaggio VACUUM secondo la tabella e cancellato.

PostgreSQL Antipattern: combattere orde di "morti"

Ma questo non accadrà immediatamente, ma i problemi con i "morti" possono essere acquisiti molto rapidamente - con ripetuti o aggiornamento di massa dei record in un grande tavolo, e poco dopo incontrerai la stessa situazione VACUUM non sarà in grado di aiutare.

# 1: Mi piace spostarlo

Supponiamo che il tuo metodo stia lavorando sulla logica aziendale e all'improvviso si rende conto che sarebbe necessario aggiornare il campo X in alcuni record:

UPDATE tbl SET X = <newX> WHERE pk = $1;

Quindi, man mano che l'esecuzione procede, risulta che anche il campo Y dovrebbe essere aggiornato:

UPDATE tbl SET Y = <newY> WHERE pk = $1;

... e poi anche Z - perché perdere tempo in sciocchezze?

UPDATE tbl SET Z = <newZ> WHERE pk = $1;

Quante versioni di questo record abbiamo ora nel database? Sì, 4 pezzi! Di questi, uno è rilevante e 3 dovranno essere ripuliti dopo di te da [auto]VACUUM.

Non farlo in questo modo! Utilizzo aggiornando tutti i campi in un'unica richiesta — quasi sempre la logica del metodo può essere modificata in questo modo:

UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;

#2: L'uso È DISTINTO DA, Luke!

Quindi, volevi ancora aggiornare molti, molti record in una tabella (durante l'uso di uno script o di un convertitore, ad esempio). E qualcosa del genere entra nella sceneggiatura:

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

Una richiesta approssimativamente in questa forma avviene abbastanza spesso e quasi sempre non per compilare un nuovo campo vuoto, ma per correggere alcuni errori nei dati. Allo stesso tempo, lei stessa la correttezza dei dati esistenti non viene affatto presa in considerazione - ma invano! Cioè, il documento viene riscritto, anche se conteneva esattamente ciò che si voleva, ma perché? Risolviamolo:

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

Molte persone non sono a conoscenza dell'esistenza di un operatore così meraviglioso, quindi ecco un riassunto IS DISTINCT FROM e altri operatori logici per aiutare:
PostgreSQL Antipattern: combattere orde di "morti"
... e un po' di operazioni su complesse ROW()-espressioni:
PostgreSQL Antipattern: combattere orde di "morti"

#3: Riconosco la mia dolce metà... bloccando

vengono lanciati due processi paralleli identici, ognuno dei quali tenta di contrassegnare la voce che è “in corso”:

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

Anche se questi processi effettivamente eseguono operazioni indipendenti l’uno dall’altro, ma all’interno dello stesso ID, il secondo client verrà “bloccato” su questa richiesta fino al completamento della prima transazione.

Decisione n. 1: il compito si riduce a quello precedente

Aggiungiamolo di nuovo IS DISTINCT FROM:

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

In questo modulo, la seconda richiesta semplicemente non cambierà nulla nel database, tutto è già come dovrebbe essere, quindi non si verificherà il blocco. Successivamente, elaboriamo il fatto di "non trovare" il record nell'algoritmo applicato.

Decisione n. 2: blocchi consultivi

Un argomento importante per un articolo separato, in cui puoi leggere modalità di applicazione e “rastrello” del blocco delle raccomandazioni.

Decisione n. 3: chiamate stupide

Ma questo è esattamente ciò che dovrebbe accaderti lavoro simultaneo con lo stesso record? Oppure, ad esempio, hai sbagliato con gli algoritmi per richiamare la logica di business sul lato client? E se ci pensi?..

Fonte: habr.com

Aggiungi un commento