Egenskaperna hos de interna mekanismerna i PostgreSQL gör att den är väldigt snabb i vissa situationer och "inte särskilt snabb" i andra. Idag kommer vi att fokusera på ett klassiskt exempel på en konflikt mellan hur ett DBMS fungerar och vad utvecklaren gör med det - UPPDATERING vs MVCC-principer.
Kort berättelse från
När en rad modifieras av ett UPDATE-kommando, utförs faktiskt två operationer: DELETE och INSERT. I nuvarande version av strängen xmax sätts lika med numret på transaktionen som utförde UPPDATERING. Sedan skapas det en ny version samma rad; dess xmin-värde sammanfaller med xmax-värdet för den tidigare versionen.
En tid efter att denna transaktion har slutförts, den gamla eller nya versionen, beroende på COMMIT/ROOLBACK
, kommer att erkännas "död" (döda tuplar) när man passerar VACUUM
enligt tabellen och rensad.
Men detta kommer inte att hända direkt, men problem med de "döda" kan förvärvas mycket snabbt - med upprepade eller
#1: Jag gillar att flytta den
Låt oss säga att din metod arbetar med affärslogik, och plötsligt inser den att det skulle vara nödvändigt att uppdatera X-fältet i någon post:
UPDATE tbl SET X = <newX> WHERE pk = $1;
Sedan, när exekveringen fortskrider, visar det sig att Y-fältet också bör uppdateras:
UPDATE tbl SET Y = <newY> WHERE pk = $1;
... och sedan även Z - varför slösa tid på småsaker?
UPDATE tbl SET Z = <newZ> WHERE pk = $1;
Hur många versioner av denna post har vi nu i databasen? Japp, 4 stycken! Av dessa är en relevant och 3 måste städas upp efter dig med [auto]VACUUM.
Gör det inte på det här sättet! Använda sig av uppdatera alla fält i en begäran — nästan alltid logiken i metoden kan ändras så här:
UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;
#2: Användning skiljer sig FRÅN, Luke!
Så du ville fortfarande
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2;
En begäran i ungefär denna form förekommer ganska ofta och nästan alltid att inte fylla i ett tomt nytt fält, utan att rätta till vissa fel i uppgifterna. Samtidigt hon själv riktigheten av befintliga uppgifter beaktas inte alls - men förgäves! Det vill säga skivan skrivs om, även om den innehöll precis det som önskades – men varför? Låt oss fixa det:
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM <newX>;
Många människor är inte medvetna om existensen av en sådan underbar operatör, så här är ett fuskblad på IS DISTINCT FROM
och andra logiska operatorer för att hjälpa:
... och lite om operationer på komplex ROW()
-uttryck:
#3: Jag känner igen min älskling genom att... blockera
håller på att lanseras två identiska parallella processer, som var och en försöker markera posten att den är "pågår":
UPDATE tbl SET processing = TRUE WHERE pk = $1;
Även om dessa processer faktiskt gör saker oberoende av varandra, men inom samma ID, kommer den andra klienten att "låsas" på denna begäran tills den första transaktionen är slutförd.
Beslut nr 1: uppgiften reduceras till den föregående
Låt oss bara lägga till det igen IS DISTINCT FROM
:
UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;
I det här formuläret kommer den andra begäran helt enkelt inte att ändra något i databasen, allt är redan som det ska vara - därför kommer blockering inte att inträffa. Därefter behandlar vi faktumet att "inte hitta" posten i den tillämpade algoritmen.
Beslut nr 2: rådgivande lås
Ett stort ämne för en separat artikel, där du kan läsa om
Beslut nr 3: dumma samtal
Men det är precis vad som ska hända dig samtidigt arbete med samma rekord? Eller krånglade du till exempel med algoritmerna för att anropa affärslogik på klientsidan? Och om du tänker efter?..
Källa: will.com