Upekee wa mifumo ya ndani ya PostgreSQL inaruhusu iwe haraka sana katika hali zingine na "sio haraka sana" kwa zingine. Leo tutazingatia mfano wa kawaida wa mzozo kati ya jinsi DBMS inavyofanya kazi na kile msanidi hufanya nayo - UPDATE dhidi ya kanuni za MVCC.
Hadithi fupi kutoka
Wakati safu mlalo inarekebishwa na amri ya UPDATE, shughuli mbili zinafanywa: DELETE na INSERT. KATIKA toleo la sasa la kamba xmax imewekwa sawa na idadi ya shughuli iliyofanya USASISHAJI. Kisha inaundwa toleo jipya mstari huo huo; thamani yake ya xmin inalingana na thamani ya xmax ya toleo la awali.
Muda fulani baada ya shughuli hii kukamilika, toleo la zamani au jipya, kulingana na COMMIT/ROOLBACK
, itatambuliwa "wafu" (wafuasi waliokufa) ΠΏΡΠΈ ΠΏΡΠΎΡ
ΠΎΠ΄Π΅ VACUUM
kulingana na meza na kusafishwa.
Lakini hii haitatokea mara moja, lakini shida na "wafu" zinaweza kupatikana haraka sana - kwa kurudiwa au
#1: Ninapenda Kuihamisha
Wacha tuseme njia yako inafanya kazi kwa mantiki ya biashara, na ghafla inagundua kuwa itakuwa muhimu kusasisha uga wa X katika rekodi fulani:
UPDATE tbl SET X = <newX> WHERE pk = $1;
Halafu, wakati utekelezaji unavyoendelea, inabadilika kuwa uwanja wa Y unapaswa kusasishwa pia:
UPDATE tbl SET Y = <newY> WHERE pk = $1;
... na kisha pia Z - kwa nini upoteze wakati kwenye vitapeli?
UPDATE tbl SET Z = <newZ> WHERE pk = $1;
Je, sasa tuna matoleo mangapi ya rekodi hii kwenye hifadhidata? Ndio, vipande 4! Kati ya hizi, moja inafaa, na 3 italazimika kusafishwa baada yako na [otomatiki] VACUUM.
Usifanye hivi! Tumia kusasisha sehemu zote katika ombi moja - karibu kila wakati mantiki ya njia inaweza kubadilishwa kama hii:
UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;
#2: Matumizi NI TOFAUTI NA, Luka!
Kwa hivyo, bado ulitaka
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2;
Ombi katika takriban fomu hii hutokea mara nyingi na karibu kila mara si kujaza sehemu mpya tupu, lakini kurekebisha baadhi ya makosa katika data. Wakati huo huo, yeye mwenyewe usahihi wa data zilizopo hauzingatiwi kabisa - lakini bure! Hiyo ni, rekodi inaandikwa upya, hata ikiwa ilikuwa na kile kilichotakiwa - lakini kwa nini? Hebu turekebishe:
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM <newX>;
Watu wengi hawajui juu ya uwepo wa mwendeshaji mzuri kama huyo, kwa hivyo hapa kuna karatasi ya kudanganya IS DISTINCT FROM
na waendeshaji wengine wenye mantiki kusaidia:
... na kidogo juu ya shughuli kwenye tata ROW()
-maneno:
#3: Namtambua mpenzi wangu kwa... kumzuia
zinazinduliwa michakato miwili inayofanana, ambayo kila moja inajaribu kutia alama kwenye ingizo kwamba "inaendelea":
UPDATE tbl SET processing = TRUE WHERE pk = $1;
Hata kama taratibu hizi zitafanya mambo bila kujali, lakini ndani ya kitambulisho sawa, mteja wa pili "atafungwa" kwa ombi hili hadi muamala wa kwanza ukamilike.
Suluhisho # 1: kazi imepunguzwa hadi ya awali
Wacha tuiongeze tena IS DISTINCT FROM
:
UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;
Katika fomu hii, ombi la pili halitabadilisha chochote kwenye hifadhidata, kila kitu tayari ni kama inavyopaswa kuwa - kwa hivyo, kuzuia haitatokea. Ifuatayo, tunashughulikia ukweli wa "kutopata" rekodi katika algorithm iliyotumika.
Suluhisho # 2: kufuli za ushauri
Mada kubwa kwa makala tofauti, ambayo unaweza kusoma kuhusu
Suluhisho # 3: simu za kijinga
Lakini hii ndio hasa inapaswa kutokea kwako kazi ya wakati mmoja na rekodi sawa? Au umevuruga kanuni za kuita mantiki ya biashara kwenye upande wa mteja, kwa mfano? Na ikiwa unafikiria juu yake? ..
Chanzo: mapenzi.com