PostgreSQL-ի ներքին մեխանիզմների առանձնահատկությունները թույլ են տալիս որոշ իրավիճակներում այն լինել շատ արագ, իսկ մյուսներում՝ «ոչ շատ արագ»: Այսօր մենք կկենտրոնանանք հակասության դասական օրինակի վրա, թե ինչպես է աշխատում DBMS-ը և ինչ է անում մշակողը դրա հետ. UPDATE ընդդեմ MVCC սկզբունքների.
Համառոտ պատմություն ից
Երբ տողը փոփոխվում է UPDATE հրամանով, իրականում կատարվում է երկու գործողություն՝ DELETE և INSERT: IN տողի ընթացիկ տարբերակը xmax-ը հավասար է այն գործարքի թվին, որն իրականացրել է UPDATE-ը: Հետո այն ստեղծվում է նոր տարբերակ նույն գիծը; դրա xmin արժեքը համընկնում է նախորդ տարբերակի xmax արժեքի հետ:
Այս գործարքի ավարտից որոշ ժամանակ անց՝ հին կամ նոր տարբերակը՝ կախված COMMIT/ROOLBACK
, կճանաչվի «մեռած» (մեռած tuples) անցնելիս VACUUM
ըստ աղյուսակի և մաքրվել:
Բայց դա անմիջապես տեղի չի ունենա, բայց «մահացածների» հետ կապված խնդիրները կարելի է շատ արագ ձեռք բերել՝ կրկնվող կամ
#1. Ես սիրում եմ այն տեղափոխել
Ենթադրենք, որ ձեր բիզնեսի տրամաբանական մեթոդն ինքնին աշխատում է, և հանկարծ նա հասկանում է, որ անհրաժեշտ կլինի թարմացնել X դաշտը ինչ-որ գրառումում.
UPDATE tbl SET X = <newX> WHERE pk = $1;
Այնուհետև, երբ կատարումը զարգանում է, պարզվում է, որ Y դաշտը նույնպես պետք է թարմացվի.
UPDATE tbl SET Y = <newY> WHERE pk = $1;
... և հետո նաև Զ - ինչու՞ ժամանակ վատնել մանրուքների վրա:
UPDATE tbl SET Z = <newZ> WHERE pk = $1;
Այս գրառման քանի՞ տարբերակ ունենք հիմա տվյալների բազայում: Այո, 4 հատ: Դրանցից մեկը տեղին է, և 3-ը պետք է մաքրվեն ձեր հետևից [ավտո]վակուումով։
Մի արեք դա այսպես. Օգտագործեք թարմացնել բոլոր դաշտերը մեկ հարցումով — գրեթե միշտ մեթոդի տրամաբանությունը կարելի է փոխել այսպես.
UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;
# 2. Օգտագործումը տարբերվում է, Լյուկ:
Այսպիսով, դուք դեռ ցանկանում եք
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2;
Սրա նման խնդրանքը բավականին հաճախ է հանդիպում և գրեթե միշտ ոչ թե դատարկ նոր դաշտ լրացնելու, այլ տվյալների որոշ սխալներ ուղղելու համար: Միևնույն ժամանակ, նա ինքը առկա տվյալների ճշգրտությունն ընդհանրապես հաշվի չի առնվում - բայց ապարդյուն! Այսինքն՝ ձայնագրությունը վերաշարադրվում է, նույնիսկ եթե այն պարունակում էր հենց այն, ինչ ուզում էին, բայց ինչո՞ւ։ Եկեք շտկենք.
UPDATE tbl SET X = <newX> WHERE pk BETWEEN $1 AND $2 AND X IS DISTINCT FROM <newX>;
Շատերը տեղյակ չեն նման հրաշալի օպերատորի գոյության մասին, ուստի ահա մի խաբեբա թերթիկ IS DISTINCT FROM
և այլ տրամաբանական օպերատորներ, որոնք կօգնեն.
... և մի փոքր համալիրի վրա գործողությունների մասին ROW()
-արտահայտությունները:
#3. Ես ճանաչում եմ իմ սիրելիին... արգելափակելով
գործարկվում են երկու նույնական զուգահեռ գործընթացներ, որոնցից յուրաքանչյուրը փորձում է նշել մուտքը, որ այն «ընթացքի մեջ է».
UPDATE tbl SET processing = TRUE WHERE pk = $1;
Նույնիսկ եթե այս գործընթացներն իրականում ինչ-որ բան անում են միմյանցից անկախ, բայց նույն ID-ի շրջանակներում, երկրորդ հաճախորդը «կողպված կլինի» այս հարցումով մինչև առաջին գործարքի ավարտը:
Լուծում թիվ 1առաջադրանքը կրճատվում է նախորդին
Պարզապես նորից ավելացնենք IS DISTINCT FROM
:
UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;
Այս ձևով երկրորդ հարցումը պարզապես ոչինչ չի փոխի տվյալների բազայում, ամեն ինչ արդեն այնպես է, ինչպես պետք է լինի, հետևաբար, արգելափակում չի լինի: Այնուհետև մենք մշակում ենք կիրառական ալգորիթմում գրառումը «չգտնելու» փաստը:
Լուծում թիվ 2Խորհրդատվական կողպեքներ
Մեծ թեմա առանձին հոդվածի համար, որի մասին կարող եք կարդալ
Լուծում թիվ 3: Հիմար զանգեր
Բայց սա հենց այն է, ինչ պետք է պատահի ձեզ հետ միաժամանակյա աշխատանք նույն ձայնագրությամբ? Թե՞ դուք խառնվել եք, օրինակ, հաճախորդի կողմից բիզնես տրամաբանություն կանչելու ալգորիթմներին: Իսկ եթե մտածեք դրա մասին...
Source: www.habr.com