Antipatterns PostgreSQL: lupta împotriva hoardelor de „morți”

Particularitățile mecanismelor interne ale PostgreSQL îi permit să fie foarte rapid în unele situații și „nu foarte rapid” în altele. Astăzi ne vom concentra pe un exemplu clasic de conflict între modul în care funcționează un DBMS și ceea ce face dezvoltatorul cu el - UPDATE vs principiile MVCC.

Scurtă poveste de la grozav articol:

Când un rând este modificat printr-o comandă UPDATE, sunt efectiv efectuate două operații: DELETE și INSERT. ÎN versiunea curentă a șirului xmax este setat egal cu numărul tranzacției care a efectuat UPDATE. Apoi este creat o noua versiune aceeași linie; valoarea sa xmin coincide cu valoarea xmax a versiunii anterioare.

La ceva timp după finalizarea acestei tranzacții, versiunea veche sau nouă, în funcție de COMMIT/ROOLBACK, vor fi recunoscute „mort” (tupluri morți) la trecere VACUUM conform tabelului și șters.

Antipatterns PostgreSQL: lupta împotriva hoardelor de „morți”

Dar acest lucru nu se va întâmpla imediat, dar problemele cu „morții” pot fi dobândite foarte repede - cu repetate sau actualizarea în masă a înregistrărilor într-o masă mare, iar puțin mai târziu veți întâlni aceeași situație VACUUM nu va putea ajuta.

#1: Îmi place să-l mut

Să presupunem că metoda dvs. funcționează pe logica afacerii și dintr-o dată își dă seama că ar fi necesar să actualizați câmpul X într-o înregistrare:

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

Apoi, pe măsură ce execuția progresează, se dovedește că și câmpul Y ar trebui actualizat:

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

... și apoi și Z - de ce să pierdeți timpul cu fleacuri?

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

Câte versiuni ale acestei înregistrări avem acum în baza de date? Da, 4 bucăți! Dintre acestea, una este relevantă, iar 3 vor trebui curățate după tine prin [auto]VACUUM.

Nu face acest lucru! Utilizare actualizarea tuturor câmpurilor într-o singură solicitare — aproape întotdeauna logica metodei poate fi schimbată astfel:

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

#2: Utilizarea ESTE DIFERENT DE, Luke!

Deci, încă ai vrut actualizați multe, multe înregistrări într-un tabel (în timpul utilizării unui script sau a unui convertor, de exemplu). Și ceva de genul acesta zboară în scenariu:

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

O solicitare în aproximativ acest formular apare destul de des și aproape întotdeauna nu pentru a completa un câmp nou gol, ci pentru a corecta unele erori în date. În același timp, ea însăși corectitudinea datelor existente nu este luată în considerare deloc - dar în zadar! Adică înregistrarea este rescrisă, chiar dacă conținea exact ceea ce se dorea – dar de ce? Hai să o reparăm:

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

Mulți oameni nu sunt conștienți de existența unui astfel de operator minunat, așa că iată o foaie de cheat IS DISTINCT FROM și alți operatori logici pentru a ajuta:
Antipatterns PostgreSQL: lupta împotriva hoardelor de „morți”
... și puțin despre operațiunile pe complex ROW()-expresii:
Antipatterns PostgreSQL: lupta împotriva hoardelor de „morți”

#3: Îmi recunosc iubita prin... blocare

sunt lansate două procese paralele identice, dintre care fiecare încearcă să marcheze intrarea că este „în desfășurare”:

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

Chiar dacă aceste procese realizează lucruri independente unele de altele, dar în cadrul aceluiași ID, al doilea client va fi „blocat” la această solicitare până la finalizarea primei tranzacții.

Soluția #1: sarcina se reduce la cea anterioară

Să-l adăugăm din nou IS DISTINCT FROM:

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

În această formă, a doua solicitare pur și simplu nu va schimba nimic în baza de date, totul este deja așa cum ar trebui să fie - prin urmare, blocarea nu va avea loc. În continuare, procesăm faptul de a „nu găsi” înregistrarea în algoritmul aplicat.

Soluția #2: încuietori de consiliere

Un subiect mare pentru un articol separat, în care puteți citi despre metode de aplicare și „rake” de blocare recomandată.

Soluția #3: apeluri stupide

Dar asta este exact ceea ce ar trebui să vi se întâmple lucru simultan cu aceeași înregistrare? Sau ai greșit cu algoritmii pentru apelarea logicii de afaceri din partea clientului, de exemplu? Și dacă te gândești bine?...

Sursa: www.habr.com

Adauga un comentariu