Veçoritë e mekanizmave të brendshëm të PostgreSQL e lejojnë atë të jetë shumë i shpejtë në disa situata dhe "jo shumë i shpejtë" në të tjera. Sot do të përqendrohemi në një shembull klasik të një konflikti midis mënyrës se si funksionon një DBMS dhe çfarë bën zhvilluesi me të - Parimet UPDATE vs MVCC.
Histori e shkurtër nga :
Kur një rresht modifikohet nga një komandë UPDATE, në të vërtetë kryhen dy operacione: DELETE dhe INSERT. NË versioni aktual i vargut xmax është vendosur i barabartë me numrin e transaksionit që ka kryer PËRDITËSIM. Pastaj krijohet një version të ri e njëjta linjë; vlera e tij xmin përkon me vlerën xmax të versionit të mëparshëm.
Disa kohë pas përfundimit të këtij transaksioni, versioni i vjetër ose i ri, në varësi të COMMIT/ROOLBACK, do të njihet "i vdekur" (tuples të vdekur) kur kalon VACUUM sipas tabelës dhe pastrohet.

Por kjo nuk do të ndodhë menjëherë, por problemet me "të vdekurit" mund të fitohen shumë shpejt - me të përsëritura ose në një tavolinë të madhe, dhe pak më vonë do të hasni të njëjtën situatë .
#1: Më pëlqen ta lëviz
Le të themi se metoda juaj e logjikës së biznesit po funksionon vetë, dhe papritmas kupton se do të ishte e nevojshme të përditësohej fusha X në një rekord:
UPDATE tbl SET X = <newX> WHERE pk = $1;Pastaj, ndërsa ekzekutimi përparon, rezulton se fusha Y gjithashtu duhet të përditësohet:
UPDATE tbl SET Y = <newY> WHERE pk = $1;... dhe më pas edhe Z - pse të humbim kohë me gjëra të vogla?
UPDATE tbl SET Z = <newZ> WHERE pk = $1;Sa versione të këtij regjistrimi kemi tani në bazën e të dhënave? Po, 4 copë! Nga këto, një është e rëndësishme dhe 3 do të duhet të pastrohen pas jush me [auto]VACUUM.
Mos e bëni në këtë mënyrë! Përdorni përditësimi i të gjitha fushave në një kërkesë - pothuajse gjithmonë logjika e metodës mund të ndryshohet si kjo:
UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;#2: Përdorimi është i ndryshëm nga, Luke!
Pra, ju ende dëshironit (për shembull gjatë përdorimit të një skripti ose konverteri). Dhe diçka e tillë hyn në skenar:
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2;Një kërkesë afërsisht në këtë formë ndodh mjaft shpesh dhe pothuajse gjithmonë jo për të plotësuar një fushë të re bosh, por për të korrigjuar disa gabime në të dhëna. Në të njëjtën kohë, ajo vetë korrektësia e të dhënave ekzistuese nuk merret fare parasysh - por më kot! Kjo do të thotë, procesverbali rishkruhet, edhe nëse përmbante saktësisht atë që kërkohej - por pse? Le ta rregullojmë:
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM <newX>; Shumë njerëz nuk janë të vetëdijshëm për ekzistencën e një operatori kaq të mrekullueshëm, kështu që këtu është një fletë mashtrimi IS DISTINCT FROM dhe operatorë të tjerë logjikë për të ndihmuar:

... dhe pak për operacionet në kompleks ROW()-shprehjet:

#3: E njoh të dashurën time duke... bllokuar
janë duke u nisur dy procese identike paralele, secila prej të cilave përpiqet të shënojë hyrjen se është "në vazhdim":
UPDATE tbl SET processing = TRUE WHERE pk = $1;Edhe nëse këto procese në fakt bëjnë gjëra të pavarura nga njëri-tjetri, por brenda të njëjtës ID, klienti i dytë do të "kyçet" në këtë kërkesë derisa të përfundojë transaksioni i parë.
Zgjidhja numër 1: detyra reduktohet në atë të mëparshme
Le ta shtojmë sërish IS DISTINCT FROM:
UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;Në këtë formë, kërkesa e dytë thjesht nuk do të ndryshojë asgjë në bazën e të dhënave, gjithçka tashmë është ashtu siç duhet - prandaj, bllokimi nuk do të ndodhë. Më pas, ne përpunojmë faktin e "mos gjetjes" së rekordit në algoritmin e aplikuar.
Zgjidhja numër 2: bravë këshilluese
Një temë e madhe për një artikull të veçantë, në të cilin mund të lexoni .
Zgjidhja numër 3: thirrje budallaqe
Por kjo është pikërisht ajo që duhet të ndodhë me ju punë e njëkohshme me të njëjtin rekord? Apo i keni ngatërruar algoritmet për thirrjen e logjikës së biznesit në anën e klientit, për shembull? Dhe nëse mendoni për këtë? ..
Burimi: www.habr.com
