PostgreSQL-ren barne-mekanismoen berezitasunek egoera batzuetan oso azkarra eta beste batzuetan "ez oso azkarra" izatea ahalbidetzen dute. Gaur DBMS baten funtzionamenduaren eta garatzaileak harekin egiten duenaren arteko gatazka baten adibide klasiko batean zentratuko gara - UPDATE vs MVCC printzipioak.
Istorio laburra
UPDATE komando baten bidez errenkada bat aldatzen denean, bi eragiketa egiten dira benetan: DELETE eta INSERT. IN katearen egungo bertsioa xmax EGUNERAZIOA egin duen transakzioaren kopuruaren berdina ezartzen da. Orduan sortzen da bertsio berri bat lerro bera; bere xmin balioa aurreko bertsioaren xmax balioarekin bat dator.
Transakzio hau amaitu eta denbora batera, bertsio zaharra edo berria, arabera COMMIT/ROOLBACK
, aitortuko da "hildako" (hildako tuplak) pasatzean VACUUM
taularen arabera eta garbitu.
Baina hori ez da berehala gertatuko, baina "hildakoen" arazoak oso azkar lor daitezke - errepikatu edo
#1: Mugitzea gustatzen zait
Demagun zure metodoa negozio-logikan lan egiten ari dela, eta bat-batean konturatzen dela X eremua erregistro batzuetan eguneratu beharko litzatekeela:
UPDATE tbl SET X = <newX> WHERE pk = $1;
Orduan, exekuzioa aurrera doan heinean, Y eremua ere eguneratu beharko litzateke:
UPDATE tbl SET Y = <newY> WHERE pk = $1;
... eta gero Z ere - zergatik galdu denbora huskeriatan?
UPDATE tbl SET Z = <newZ> WHERE pk = $1;
Disko honen zenbat bertsio ditugu orain datu-basean? Bai, 4 pieza! Horietatik bat garrantzitsua da, eta 3 garbitu beharko dira zure ondoren [auto]VACUUM bidez.
Ez egin horrela! Erabili eremu guztiak eskaera bakarrean eguneratzea β ia beti metodoaren logika honela alda daiteke:
UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;
#2: Erabilera DESBERDINTA DA, Luke!
Beraz, oraindik nahi zenuen
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2;
Gutxi gorabehera inprimaki honetako eskaera bat sarritan gertatzen da eta ia beti eremu berri hutsik ez betetzeko, datuetan akats batzuk zuzentzeko baizik. Aldi berean, bera dauden datuen zuzentasuna ez da batere kontuan hartzen - baina alferrik! Hau da, diskoa berridatzi egiten da, nahi zena zehatz-mehatz jaso bazuen ere, baina zergatik? Konpon dezagun:
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM <newX>;
Jende askok ez daki horrelako operadore zoragarri baten existentziaz, beraz, hona hemen iruzur orri bat IS DISTINCT FROM
eta beste operadore logiko batzuk laguntzeko:
... eta konplexuen gaineko eragiketei buruz apur bat ROW()
-esamoldeak:
#3: Nire maitea ezagutzen dut... blokeatzeagatik
martxan jartzen ari dira bi prozesu paralelo berdin, eta horietako bakoitzak sarrera "abian" dela markatzen saiatzen da:
UPDATE tbl SET processing = TRUE WHERE pk = $1;
Nahiz eta prozesu hauek gauza bata bestearengandik independente egiten dituzten, baina ID beraren barruan, bigarren bezeroa eskaera honetan "blokeatuta" egongo da lehenengo transakzioa burutu arte.
1. irtenbidea: ataza aurrekora murrizten da
Gehi dezagun berriro IS DISTINCT FROM
:
UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;
Inprimaki honetan, bigarren eskaerak ez du datu-basean ezer aldatuko, dena behar den bezala dago jada; beraz, ez da blokeorik gertatuko. Ondoren, aplikatutako algoritmoan erregistroa "ez aurkitzea" prozesatzen dugu.
2. irtenbidea: aholkularitzako sarrailak
Aparteko artikulu baterako gai handi bat, zeinetan irakur dezakezun
3. irtenbidea: dei ergelak
Baina horixe da zuri gertatu behar zaizuna aldibereko lana disko berdinarekin? Edo bezeroaren aldetik negozio-logikari deitzeko algoritmoekin nahastu zenuen, adibidez? Eta pentsatzen baduzu?...
Iturria: www.habr.com