Die eienaardighede van die interne meganismes van PostgreSQL laat dit in sommige situasies baie vinnig en in ander "nie baie vinnig" wees nie. Vandag sal ons fokus op 'n klassieke voorbeeld van 'n konflik tussen hoe 'n DBMS werk en wat die ontwikkelaar daarmee doen - UPDATE vs MVCC-beginsels.
Kort storie van
Wanneer 'n ry deur 'n UPDATE-opdrag gewysig word, word twee bewerkings eintlik uitgevoer: DELETE en INSERT. IN huidige weergawe van die string xmax is gelyk aan die nommer van die transaksie wat die UPDATE uitgevoer het. Dan word dit geskep 'n nuwe weergawe dieselfde lyn; sy xmin-waarde val saam met die xmax-waarde van die vorige weergawe.
Geruime tyd nadat hierdie transaksie voltooi is, die ou of nuwe weergawe, afhangende van COMMIT/ROOLBACK
, erken sal word "dood" (dooie tupels) wanneer jy verbygaan VACUUM
volgens die tabel en skoongemaak.
Maar dit sal nie dadelik gebeur nie, maar probleme met die "dooies" kan baie vinnig opgedoen word - met herhaalde of
#1: Ek hou daarvan om dit te skuif
Kom ons sê jou metode werk op besigheidslogika, en skielik besef dit dat dit nodig sal wees om die X-veld in een of ander rekord op te dateer:
UPDATE tbl SET X = <newX> WHERE pk = $1;
Dan, soos die uitvoering vorder, blyk dit dat die Y-veld ook opgedateer moet word:
UPDATE tbl SET Y = <newY> WHERE pk = $1;
... en dan ook Z - hoekom tyd mors op kleinighede?
UPDATE tbl SET Z = <newZ> WHERE pk = $1;
Hoeveel weergawes van hierdie rekord het ons nou in die databasis? Ja, 4 stukke! Hiervan is een relevant, en 3 sal na jou skoongemaak moet word deur [outo]VAKUUM.
Moenie dit op hierdie manier doen nie! Gebruik opdatering van alle velde in een versoek — byna altyd kan die logika van die metode soos volg verander word:
UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;
#2: Gebruik IS ONDERSKEI VAN, Luke!
So, jy wou nog steeds
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2;
'n Versoek in ongeveer hierdie vorm kom redelik gereeld en byna altyd voor om nie 'n leë nuwe veld in te vul nie, maar om sommige foute in die data reg te stel. Terselfdertyd het sy self die korrektheid van bestaande data word glad nie in ag geneem nie - maar tevergeefs! Dit wil sê, die rekord word oorgeskryf, al bevat dit presies wat verlang word – maar hoekom? Kom ons maak dit reg:
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM <newX>;
Baie mense is nie bewus van die bestaan van so 'n wonderlike operateur nie, so hier is 'n cheat sheet op IS DISTINCT FROM
en ander logiese operateurs om te help:
... en 'n bietjie oor bedrywighede op kompleks ROW()
-uitdrukkings:
#3: Ek herken my liefling deur... te blokkeer
word van stapel gestuur twee identiese parallelle prosesse, wat elkeen probeer om die inskrywing te merk dat dit "aan die gang" is:
UPDATE tbl SET processing = TRUE WHERE pk = $1;
Selfs al doen hierdie prosesse eintlik dinge onafhanklik van mekaar, maar binne dieselfde ID, sal die tweede kliënt op hierdie versoek “gesluit” wees totdat die eerste transaksie afgehandel is.
Oplossing 1: die taak word verminder na die vorige een
Kom ons voeg dit net weer by IS DISTINCT FROM
:
UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;
In hierdie vorm sal die tweede versoek eenvoudig niks in die databasis verander nie, alles is reeds soos dit moet wees - daarom sal blokkering nie plaasvind nie. Vervolgens verwerk ons die feit dat ons nie die rekord in die toegepaste algoritme vind nie.
Oplossing 2: raadgewende slotte
'n Groot onderwerp vir 'n aparte artikel, waaroor jy kan lees
Oplossing 3: dom oproepe
Maar dit is presies wat met jou moet gebeur gelyktydige werk met dieselfde rekord? Of het jy byvoorbeeld gemors met die algoritmes om besigheidslogika aan die kliëntkant te noem? En as jy daaraan dink? ..
Bron: will.com