PostgreSQL Antipatternləri: tətikdən yan keçərək məlumatları dəyişdirin

Gec-tez bir çoxları cədvəl qeydlərində nəyisə kütləvi şəkildə düzəltmək ehtiyacı ilə üzləşirlər. Məndə artıq var bunu daha yaxşı necə edəcəyimi söyləyin, və necə - bunu etməmək daha yaxşıdır. Bu gün kütləvi yeniləmənin ikinci aspekti haqqında danışacağam - tetikleyiciler haqqında.

Məsələn, bir şeyi düzəltməli olduğunuz bir masada pis bir tətik asılır ON UPDATE, bütün dəyişiklikləri bəzi aqreqatlara köçürmək. Və hər şeyi yeniləməlisiniz (məsələn, yeni bir sahəni işə salın) o qədər diqqətlə etməlisiniz ki, bu aqreqatlara təsir etməsin.

Gəlin sadəcə tetikleyicileri söndürək!

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

Əslində, hamısı budur - hər şey asılıb.

Çünki ALTER TABLE qoyur Eksklüziv daxil olun- altında heç kimin paralel işləmədiyi bir kilid, hətta sadə SELECT, cədvəldən heç nə oxuya bilməyəcək. Yəni, bu əməliyyat bitənə qədər hətta “sadəcə oxumaq” istəyən hər kəs gözləyəcək. Və biz bunu xatırlayırıq UPDATE uzun müddətimiz var...

Gəlin onu tez söndürək, sonra tez yandıraq!

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

UPDATE ...;

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

Burada vəziyyət artıq yaxşıdır, gözləmə müddəti çox azdır. Ancaq yalnız iki problem bütün gözəlliyi korlayır:

  • ALTER TABLE özü uzun olanlar da daxil olmaqla masanın üzərindəki bütün digər əməliyyatları gözləyir SELECT
  • Tətiyi söndürüldükdə hər hansı bir dəyişiklik "uçmaq" cədvəldə, hətta bizimkilərdə də yoxdur. Və aqreqatlara daxil olmayacaq, baxmayaraq ki, olmalıdır. Problem!

Sessiya dəyişənlərinin idarə edilməsi

Beləliklə, əvvəlki versiyada biz əsas bir məqama rast gəldik - cədvəldəki "bizim" dəyişiklikləri "bizimki deyil"dən ayırd etməyi birtəhər öyrətməliyik. "Bizimkilər" olduğu kimi atlanır, lakin "bizimki deyil"də tetiklenir. Bunun üçün istifadə edə bilərsiniz sessiya dəyişənləri.

sessiya_replikasiya_rolu

Oxuduq təlimat:

Tətik mexanizmi də konfiqurasiya dəyişənindən təsirlənir sessiya_replikasiya_rolu. Əlavə təlimatlar olmadan aktivləşdirilib (defolt), replikasiya rolu "mənşə" (defolt) və ya "yerli" olduqda tetikleyiciler işə düşəcək. Tətiklər göstərilməklə aktivləşdirildi ENABLE REPLICA, yalnız əgər işləyəcək cari sessiya rejimi - "replika" və tətiklər göstərilməklə aktivləşdirilir ENABLE ALWAYS, cari təkrarlama rejimindən asılı olmayaraq işləyəcək.

Xüsusilə vurğulayacağam ki, qəbulu birdən hamıya şamil edilmir ALTER TABLE, lakin yalnız bizim ayrıca xüsusi əlaqəmizə. Ümumilikdə, heç bir tətbiqin işləməsi üçün:

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

Tətik daxili vəziyyət

Ancaq yuxarıdakı seçim bütün tetikleyiciler üçün eyni anda işləyir (yaxud deaktiv etmək istəmədiyiniz tetikleyicileri əvvəlcədən "alternativ" etməlisiniz). Və ehtiyacımız varsa xüsusi bir tetikleyicini "söndürün"?

Bu bizə kömək edəcək "istifadəçi" sessiya dəyişəni:

Genişləndirici parametr adları aşağıdakı kimi yazılır: genişləndirmə adı, ardınca nöqtə və sonra parametr adının özü, SQL-də tam obyekt adlarına bənzəyir. Məsələn: plpgsql.variable_conflict.
Müvafiq genişləndirmə modulunu yükləməyən proseslərdə sistemdən kənar seçimlər təyin oluna bildiyi üçün PostgreSQL iki komponentli hər hansı adlar üçün dəyərlər.

Əvvəlcə tətiyi yekunlaşdırırıq, buna bənzər bir şey:

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;
...

Yeri gəlmişkən, bu, bloklamadan, "mənfəət üçün" edilə bilər CREATE OR REPLACE tetik funksiyası üçün. Və sonra xüsusi əlaqədə "bizim" dəyişənimizi xoruzlayırıq:


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

Başqa yolları bilirsinizmi? Şərhlərdə paylaşın.

Mənbə: www.habr.com

Добавить комментарий