PostgreSQL Antipatterns: Bir tetikleyiciyi atlayarak verileri değiştirin

Er ya da geç, birçok kişi tablo kayıtlarındaki bir şeyi büyük ölçüde düzeltme ihtiyacıyla karşı karşıya kalır. zaten var bana bunu nasıl daha iyi yapacağımı anlattıve nasıl - bunu yapmamak daha iyidir. Bugün toplu güncellemenin ikinci yönünden bahsedeceğim - tetikleyiciler hakkında.

Örneğin, bir şeyi düzeltmeniz gereken bir masada kötü bir tetikleyici vardır. ON UPDATE, tüm değişiklikleri bazı kümelere aktarıyoruz. Ve bu toplamların etkilenmemesi için her şeyi (örneğin yeni bir alanı başlat) çok dikkatli bir şekilde güncellemeniz gerekir.

Hadi tetikleyicileri kapatalım!

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

Aslında hepsi bu - her şey zaten asılı.

Çünkü ALTER TABLE dayatır Özel Erişim-altında kimsenin paralel olarak koşmadığı bir kilit, basit bir kilit bile olsa SELECT, tablodan hiçbir şey okuyamayacak. Yani bu işlem tamamlanana kadar “sadece okumak” bile isteyen herkes bekleyecek. Ve bunu hatırlıyoruz UPDATE uzun bir süremiz var...

Haydi hemen kapatalım, sonra hızla açalım!

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

UPDATE ...;

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

Burada durum zaten daha iyi, bekleme süresi önemli ölçüde daha az. Ancak yalnızca iki sorun tüm güzelliği bozar:

  • ALTER TABLE kendisi uzun olanlar da dahil olmak üzere masadaki diğer tüm işlemleri bekler SELECT
  • Tetik kapalıyken, herhangi bir değişiklik "uçup gidecek" masada, bizimki bile değil. Ve olması gerektiği halde birimlere girmeyecek. Bela!

Oturum Değişkenlerini Yönetme

Dolayısıyla, önceki versiyonda temel bir noktayla karşılaştık - tetikleyiciye, tablodaki "bizim" değişikliklerimizi "bizim olmayan" değişikliklerden ayırmayı bir şekilde öğretmemiz gerekiyor. “Bizimki” olduğu gibi atlanır ve “bizim değil” tetiklenir. Bunun için kullanabilirsiniz oturum değişkenleri.

session_replication_role

Okumak Manuel:

Tetik mekanizması konfigürasyon değişkeninden de etkilenir session_replication_role. Daha fazla talimat olmadan etkinleştirildiğinde (varsayılan), tetikleyiciler çoğaltma rolü "orijin" (varsayılan) veya "yerel" olduğunda tetiklenir. Talimatlarla etkinleştirilen tetikleyiciler ENABLE REPLICA, yalnızca şu durumlarda çalışır: geçerli oturum modu - "kopya" ve tetikleyiciler belirtilerek etkinleştirilir ENABLE ALWAYS, geçerli çoğaltma modundan bağımsız olarak tetiklenecektir.

Bu ayarın aynı anda herkes için geçerli olmadığını özellikle vurgulamak isterim. ALTER TABLE, ancak yalnızca ayrı özel bağlantımıza. Toplamda, hiçbir uygulama tetikleyicisinin tetiklenmemesi için:

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

Bir tetikleyicinin içindeki durum

Ancak yukarıdaki seçenek tüm tetikleyiciler için aynı anda çalışır (veya devre dışı bırakmak istemediğiniz tetikleyicileri önceden "değiştirmeniz" gerekir). Ve eğer ihtiyacımız olursa Belirli bir tetikleyiciyi "kapat"?

Bu bize yardımcı olacaktır "kullanıcı" oturum değişkeni:

Uzantı parametre adları şu şekilde yazılır: SQL'deki tam nitelikli nesne adlarına benzer şekilde, uzantı adı, nokta ve ardından parametre adının kendisi. Örneğin: plpgsql.variable_conflict.
İlgili uzantı modülünü yüklemeyen işlemlerde sistem dışı seçenekler ayarlanabileceğinden PostgreSQL, iki bileşenli herhangi bir ismin değerleri.

İlk önce tetikleyiciyi şöyle değiştiriyoruz:

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

Bu arada, bu, engellemeden "canlı" olarak yapılabilir. CREATE OR REPLACE tetikleme işlevi için. Daha sonra özel bağlantıda “bizim” değişkenimizi ayarladık:


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

Başka yollar biliyor musun? Yorumlarda paylaşın.

Kaynak: habr.com