sql >> Databasteknik >  >> RDS >> PostgreSQL

Dödläge i PostgreSQL när UPDATE körs

I PostgreSQL kommer raderna att låsas när de uppdateras -- i själva verket fungerar det så här att varje tupel (version av en rad) har ett systemfält som heter xmin för att indikera vilken transaktion som gjorde att tuppeln strömmade (genom infogning eller uppdatering) och ett systemfält som heter xmax för att ange vilken transaktion som löpte ut den tuppeln (genom uppdatering eller radering). När du kommer åt data kontrollerar den varje tupel för att avgöra om den är synlig för din transaktion, genom att kontrollera din aktiva "ögonblicksbild" mot dessa värden.

Om du kör en UPPDATERING och en tupel som matchar dina sökvillkor har en xmin som skulle göra den synlig för din ögonblicksbild och ett xmax för en aktiv transaktion, blockeras den i väntan på att transaktionen ska slutföras. Om transaktionen som först uppdaterade tuppeln rullar tillbaka, vaknar din transaktion och bearbetar raden; om den första transaktionen genomförs, vaknar din transaktion och vidtar åtgärder beroende på den aktuella transaktionsisoleringsnivån.

Uppenbarligen är ett dödläge resultatet av att detta händer med rader i olika ordning. Det finns inget radnivålås i RAM som kan erhållas för alla rader samtidigt, men om rader uppdateras i samma ordning kan du inte ha den cirkulära låsningen. Tyvärr, den föreslagna IN(1, 2) syntax garanterar inte det. Olika sessioner kan ha olika kostnadsfaktorer aktiva, en "analys"-uppgift i bakgrunden kan ändra statistik för tabellen mellan generering av en plan och den andra, eller så kan den använda en seqscan och påverkas av PostgreSQL-optimeringen som orsakar en ny seqscan för att gå med i en redan pågående och "loop runt" för att minska disk I/O.

Om du gör uppdateringarna en i taget i samma ordning, i applikationskod eller med hjälp av en markör, kommer du bara att ha en enkel blockering, inte dödläge. Men generellt sett är relationsdatabaser benägna att serialiseringsfel, och det är bäst att komma åt dem genom ett ramverk som känner igen dem baserat på SQLSTATE och automatiskt försöker göra om hela transaktionen från början. I PostgreSQL kommer ett serialiseringsfel alltid att ha en SQLSTATE på 40001 eller 40P01.

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




  1. Kan jag blanda MySQL API:er i PHP?

  2. Reguljära uttryck i SQL Server-servrar?

  3. Prestanda för sys.partitioner

  4. mysql välja int som valuta eller konvertera int till valutaformat?