PostgreSQL-Antiŝablonoj: batali kontraŭ la hordoj de "mortintoj"

La proprecoj de la internaj mekanismoj de PostgreSQL permesas al ĝi esti tre rapida en iuj situacioj kaj "ne tre rapida" en aliaj. Hodiaŭ ni koncentriĝos pri klasika ekzemplo de konflikto inter kiel funkcias DBMS kaj kion faras la programisto per ĝi - Ĝisdatigo kontraŭ MVCC-principoj.

Mallonga rakonto de bonega artikolo:

Kiam vico estas modifita per UPDATE-komando, du operacioj efektive estas faritaj: DELETE kaj INSERT. EN aktuala versio de la ŝnuro xmax estas agordita egala al la nombro de la transakcio kiu faris la ĜISDATIGON. Tiam ĝi estas kreita nova versio la sama linio; ĝia xmin valoro koincidas kun la xmax valoro de la antaŭa versio.

Iom da tempo post kiam ĉi tiu transakcio estas kompletigita, la malnova aŭ nova versio, depende de COMMIT/ROOLBACK, estos rekonita "mortintaj" (mortaj opoj) pasinte VACUUM laŭ la tabelo kaj malbaris.

PostgreSQL-Antiŝablonoj: batali kontraŭ la hordoj de "mortintoj"

Sed ĉi tio ne okazos tuj, sed problemoj kun la "mortintoj" povas esti akiritaj tre rapide - kun ripetaj aŭ amasa ĝisdatigo de rekordoj en granda tablo, kaj iom poste vi renkontos la saman situacion VACUUM ne povos helpi.

#1: Mi Ŝatas Movi ĝin

Ni diru, ke via metodo funkcias pri komerca logiko, kaj subite ĝi rimarkas, ke necesus ĝisdatigi la X-kampon en iu registro:

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

Tiam, dum la ekzekuto progresas, rezultas, ke la Y-kampo ankaŭ devus esti ĝisdatigita:

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

... kaj poste ankaŭ Z - kial perdi tempon per bagateloj?

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

Kiom da versioj de ĉi tiu disko ni nun havas en la datumbazo? Jes, 4 pecoj! El ĉi tiuj unu estas grava, kaj 3 devos esti purigitaj post vi per [aŭto]VACUUM.

Ne faru ĝin tiel! Uzu ĝisdatigante ĉiujn kampojn en unu peto — preskaŭ ĉiam la logiko de la metodo povas esti ŝanĝita jene:

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

#2: Uzo ESTAS DISTINTA DE, Luko!

Do, vi ankoraŭ volis ĝisdatigi multajn, multajn rekordojn en tabelo (dum la uzo de skripto aŭ konvertilo, ekzemple). Kaj io tia flugas en la skripton:

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

Peto en proksimume ĉi tiu formo okazas sufiĉe ofte kaj preskaŭ ĉiam ne por plenigi malplenan novan kampon, sed por korekti iujn erarojn en la datumoj. Samtempe, ŝi mem la ĝusteco de ekzistantaj datumoj tute ne estas konsiderata — sed vane! Tio estas, la rekordo estas reverkita, eĉ se ĝi enhavis ĝuste tion, kion oni volis — sed kial? Ni riparu ĝin:

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

Multaj homoj ne konscias pri la ekzisto de tia mirinda operatoro, do jen trompo IS DISTINCT FROM kaj aliaj logikaj operatoroj por helpi:
PostgreSQL-Antiŝablonoj: batali kontraŭ la hordoj de "mortintoj"
... kaj iom pri operacioj sur komplekso ROW()-esprimoj:
PostgreSQL-Antiŝablonoj: batali kontraŭ la hordoj de "mortintoj"

#3: Mi rekonas mian amatinon per... blokado

estas lanĉitaj du identaj paralelaj procezoj, ĉiu el kiuj provas marki la eniron ke ĝi estas "en progreso":

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

Eĉ se ĉi tiuj procezoj efektive faras aferojn sendepende de unu la alian, sed ene de la sama identigilo, la dua kliento estos "ŝlosita" sur ĉi tiu peto ĝis la unua transakcio estas finita.

Solvo # 1: la tasko estas reduktita al la antaŭa

Ni simple aldonu ĝin denove IS DISTINCT FROM:

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

En ĉi tiu formo, la dua peto simple ne ŝanĝos ion en la datumbazo, ĉio jam estas kiel ĝi devus esti - tial, blokado ne okazos. Poste, ni prilaboras la fakton "ne trovi" la rekordon en la aplikata algoritmo.

Solvo # 2: konsilaj seruroj

Granda temo por aparta artikolo, pri kiu vi povas legi metodoj de apliko kaj "rake" de rekomenda blokado.

Solvo # 3: stultaj vokoj

Sed ĝuste ĉi tio devus okazi al vi samtempa laboro kun la sama rekordo? Aŭ ĉu vi fuŝis kun la algoritmoj por voki komercan logikon ĉe la klienta flanko, ekzemple? Kaj se vi pensas pri tio?...

fonto: www.habr.com

Aldoni komenton