PostgreSQL антипаттерндері: «өлілер» тобымен күресу

PostgreSQL ішкі механизмдерінің ерекшеліктері оның кейбір жағдайларда өте жылдам, ал басқаларында «өте жылдам емес» болуына мүмкіндік береді. Бүгін біз ДҚБЖ қалай жұмыс істейтіні мен әзірлеуші ​​онымен не істейтіні арасындағы қайшылықтың классикалық мысалына тоқталамыз - UPDATE және MVCC принциптері.

Шағын әңгімеден тамаша мақала:

Жол ЖАҢАЛЫҚТАУ пәрменімен өзгертілгенде, шын мәнінде екі әрекет орындалады: DELETE және INSERT. IN жолдың ағымдағы нұсқасы xmax UPDATE орындаған транзакция санына тең орнатылады. Содан кейін ол құрылады жаңа нұсқасы бірдей сызық; оның xmin мәні алдыңғы нұсқаның xmax мәніне сәйкес келеді.

Осы транзакция аяқталғаннан кейін біраз уақыттан кейін ескі немесе жаңа нұсқасына байланысты COMMIT/ROOLBACK, танылатын болады «өлі» (өлі кортеждер) өтіп бара жатқанда VACUUM кестеге сәйкес және тазартылады.

PostgreSQL антипаттерндері: «өлілер» тобымен күресу

Бірақ бұл бірден болмайды, бірақ «өлілермен» проблемаларды өте тез алуға болады - қайталанатын немесе жазбаларды жаппай жаңарту үлкен үстелде, ал сәл кейінірек сіз дәл осындай жағдайға тап боласыз ВАКУУМ көмектесе алмайды.

№1: Мен оны жылжытқанды ұнатамын

Сіздің әдісіңіз іскерлік логикада жұмыс істейді делік және кенеттен ол қандай да бір жазбада X өрісін жаңарту қажет екенін түсінеді:

UPDATE tbl SET X = <newX> WHERE pk = $1;

Содан кейін, орындалу барысында, Y өрісі де жаңартылуы керек:

UPDATE tbl SET Y = <newY> WHERE pk = $1;

... сосын сонымен қатар Z - неге ұсақ-түйекке уақыт жұмсау керек?

UPDATE tbl SET Z = <newZ> WHERE pk = $1;

Қазір дерекқорда бұл жазбаның қанша нұсқасы бар? Иә, 4 дана! Олардың біреуі өзекті және 3-ін сізден кейін [авто]ВАКУУМ арқылы тазалау керек.

Бұлай істеме! Қолдану бір сұраудағы барлық өрістерді жаңарту — әрқашан дерлік әдіс логикасын келесідей өзгертуге болады:

UPDATE tbl SET X = <newX>, Y = <newY>, Z = <newZ> WHERE pk = $1;

№2: пайдалану IS DISTINCT FROM, Лука!

Сонымен, сіз әлі де қаладыңыз кестедегі көптеген, көптеген жазбаларды жаңарту (мысалы, сценарийді немесе түрлендіргішті пайдалану кезінде). Сценарийге ұқсас нәрсе ұшады:

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 және басқа логикалық операторлар көмектеседі:
PostgreSQL антипаттерндері: «өлілер» тобымен күресу
... және кешендегі операциялар туралы аз ROW()- өрнектер:
PostgreSQL антипаттерндері: «өлілер» тобымен күресу

№3: Сүйіктімді... блоктау арқылы танимын

іске қосылып жатыр екі бірдей параллель процесс, олардың әрқайсысы жазбаны «орындалуда» деп белгілеуге тырысады:

UPDATE tbl SET processing = TRUE WHERE pk = $1;

Бұл процестер іс жүзінде бір-бірінен тәуелсіз әрекеттерді орындаса да, бірақ бір идентификатор ішінде екінші клиент бірінші транзакция аяқталғанша осы сұрау бойынша «құлыпталады».

№1 шешім: тапсырма алдыңғыға қысқарады

Оны қайтадан қосайық IS DISTINCT FROM:

UPDATE tbl SET processing = TRUE WHERE pk = $1 AND processing IS DISTINCT FROM TRUE;

Бұл пішінде екінші сұрау дерекқорда ештеңені өзгертпейді, бәрі қазірдің өзінде болуы керек - сондықтан блоктау болмайды. Әрі қарай, біз қолданбалы алгоритмде жазбаның «табылмау» фактісін өңдейміз.

№2 шешім: кеңес беру құлыптары

Бөлек мақалаға арналған үлкен тақырып, ол туралы оқуға болады қолдану әдістері және ұсынымдық блоктаудың «тырмалары»..

№3 шешім: ақымақ қоңыраулар

Бірақ бұл дәл сізбен болуы керек бір жазбамен бір мезгілде жұмыс істеу? Немесе, мысалы, клиент жағында бизнес логикасын шақыруға арналған алгоритмдерді шатастырдыңыз ба? Ал ойласаңыз?..

Ақпарат көзі: www.habr.com

пікір қалдыру