PostgreSQL
 sql >> Database >  >> RDS >> PostgreSQL

Deadlock in PostgreSQL durante l'esecuzione di UPDATE

In PostgreSQL le righe verranno bloccate man mano che vengono aggiornate -- in effetti, il modo in cui funziona effettivamente è che ogni tupla (versione di una riga) ha un campo di sistema chiamato xmin per indicare quale transazione ha reso quella tupla corrente (per inserimento o aggiornamento) e un campo di sistema chiamato xmax per indicare quale transazione è scaduta quella tupla (mediante aggiornamento o eliminazione). Quando accedi ai dati, controlla ogni tupla per determinare se è visibile alla tua transazione, controllando la tua "istantanea" attiva rispetto a questi valori.

Se stai eseguendo un UPDATE e una tupla che corrisponde alle tue condizioni di ricerca ha un xmin che lo renderebbe visibile al tuo snapshot e un xmax di una transazione attiva, si blocca, in attesa del completamento della transazione. Se la transazione che per prima ha aggiornato la tupla esegue il rollback, la transazione si riattiva ed elabora la riga; se la prima transazione viene eseguita, la transazione si riattiva e prende provvedimenti in base al livello di isolamento della transazione corrente.

Ovviamente, un deadlock è il risultato di ciò che accade alle righe in ordine diverso. Non esiste un blocco a livello di riga nella RAM che può essere ottenuto per tutte le righe contemporaneamente, ma se le righe vengono aggiornate nello stesso ordine non è possibile avere il blocco circolare. Sfortunatamente, il suggerito IN(1, 2) la sintassi non lo garantisce. Diverse sessioni possono avere diversi fattori di costo attivi, un'attività di "analisi" in background può modificare le statistiche per la tabella tra la generazione di un piano e l'altra, oppure potrebbe utilizzare un seqscan ed essere influenzato dall'ottimizzazione di PostgreSQL che provoca un nuovo seqscan per unirti a uno già in corso e "loop around" per ridurre l'I/O del disco.

Se esegui gli aggiornamenti uno alla volta nello stesso ordine, nel codice dell'applicazione o utilizzando un cursore, avrai solo un semplice blocco, non deadlock. In generale, tuttavia, i database relazionali sono soggetti a errori di serializzazione ed è meglio accedervi tramite un framework che li riconoscerà in base a SQLSTATE e ritenterà automaticamente l'intera transazione dall'inizio. In PostgreSQL un errore di serializzazione avrà sempre un SQLSTATE di 40001 o 40P01.

http://www.postgresql.org/docs/current/interactive/mvcc-intro.html