PostgreSQL Antimönster: slåss mot horder av "döda"

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 bra artikel:

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.

PostgreSQL Antimönster: slåss mot horder av "döda"

Men detta kommer inte att hända direkt, men problem med de "döda" kan förvärvas mycket snabbt - med upprepade eller massuppdatering av register i ett stort bord, och lite senare kommer du att stöta på samma situation VACUUM kommer inte att kunna hjälpa.

#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 uppdatera många, många poster i en tabell (vid användning av ett skript eller konverterare, till exempel). Och något sånt här flyger in i manuset:

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:
PostgreSQL Antimönster: slåss mot horder av "döda"
... och lite om operationer på komplex ROW()-uttryck:
PostgreSQL Antimönster: slåss mot horder av "döda"

#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 appliceringsmetoder och "rake" av rekommenderad blockering.

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

Lägg en kommentar