PostgreSQL Antipatterns: триггерді айналып өтіп, деректерді өзгерту

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

Мысалы, бірдеңені түзету керек үстелде зұлым триггер ілулі тұр ON UPDATE, барлық өзгерістерді кейбір жиынтықтарға тасымалдау. Және бұл бірліктерге әсер етпеуі үшін бәрін мұқият жаңарту керек (мысалы, жаңа өрісті инициализациялау).

Триггерлерді өшірейік!

BEGIN;
  ALTER TABLE ... DISABLE TRIGGER ...;
  UPDATE ...; -- тут долго-долго
  ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;

Шындығында, бәрі - бәрі ілулі тұр.

Себебі ALTER TABLE жүктейді AccessExclusive- астында ешкім параллель жүрмейтін құлып, тіпті қарапайым SELECT, кестеден ештеңе оқи алмайды. Яғни, бұл транзакция аяқталғанша, тіпті «жай оқығысы» келетіндердің бәрі күтеді. Және бұл есімізде UPDATE бізде ұзақ...

Тез өшірейік, сосын тез қосайық!

BEGIN;
  ALTER TABLE ... DISABLE TRIGGER ...;
COMMIT;

UPDATE ...;

BEGIN;
  ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;

Мұнда жағдай қазірдің өзінде жақсырақ, күту уақыты әлдеқайда аз. Бірақ тек екі мәселе барлық сұлулықты бұзады:

  • ALTER TABLE өзі үстелдегі барлық басқа операцияларды, соның ішінде ұзақ операцияларды күтеді SELECT
  • Триггер өшірулі тұрғанда, кез келген өзгерісті «ұшып өту». кестеде, тіпті біздікі емес. Ол керек болса да, агрегаттарға кірмейді. Ақаулық!

Сеанс айнымалыларын басқару

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

сеанс_репликация_рөлі

Оқылды нұсқаулық:

Іске қосу механизміне конфигурация айнымалысы да әсер етеді сеанс_репликация_рөлі. Қосымша нұсқауларсыз (әдепкі) қосылған кезде, репликация рөлі «бастапқы» (әдепкі) немесе «жергілікті» болғанда триггерлер іске қосылады. Триггерлерді көрсету арқылы қосылды ENABLE REPLICA, болған жағдайда ғана жұмыс істейді ағымдағы сеанс режимі - "реплика" және көрсету арқылы қосылған триггерлер ENABLE ALWAYS, ағымдағы репликация режиміне қарамастан жұмыс істейді.

Мен параметр бірден барлығына қолданылмайтынын ерекше атап өткім келеді ALTER TABLE, бірақ біздің бөлек арнайы байланысымызға ғана. Ешбір қолданба триггерлері жұмыс істемеуі үшін барлығы:

SET session_replication_role = replica; -- выключили триггеры
UPDATE ...;
SET session_replication_role = DEFAULT; -- вернули в исходное состояние

Триггер ішіндегі жағдай

Бірақ жоғарыдағы опция барлық триггерлер үшін бірден жұмыс істейді (немесе өшіргіңіз келмейтін триггерлерді алдын ала «өзгерту» керек). Ал бізге қажет болса белгілі бір триггерді «өшіру».?

Бұл бізге көмектеседі «пайдаланушы» сеансының айнымалысы:

Кеңейтім параметрінің атаулары келесідей жазылады: кеңейтім аты, нүкте, содан кейін SQL тіліндегі толық жарамды нысан атауларына ұқсас параметр атауының өзі. Мысалы: plpgsql.variable_conflict.
Жүйелік емес опцияларды сәйкес кеңейтім модулін жүктемейтін процестерде орнатуға болатындықтан, PostgreSQL қабылдайды екі компоненті бар кез келген атауларға арналған мәндер.

Алдымен біз триггерді аяқтаймыз, мысалы:

BEGIN
    -- процессу конвертации можно делать все
    IF current_setting('mycfg.my_table_convert_process') = 'TRUE' THEN
        IF TG_OP IN ('INSERT', 'UPDATE') THEN
            RETURN NEW;
        ELSE
            RETURN OLD;
        END IF;
    END IF;
...

Айтпақшы, бұл «пайда үшін», бұғаттаусыз, арқылы жасалуы мүмкін CREATE OR REPLACE триггер функциясы үшін. Содан кейін арнайы қосылымда біз «біздің» айнымалыны аламыз:


SET mycfg.my_table_convert_process = 'TRUE';
UPDATE ...;
SET mycfg.my_table_convert_process = ''; -- вернули в исходное состояние

Басқа жолдарды білесіз бе? Пікірлерде бөлісіңіз.

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

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