Antipatróns de PostgreSQL: cambia os datos sen pasar un disparador

Tarde ou cedo, moitos enfróntanse á necesidade de arranxar masivamente algo nos rexistros da táboa. Xa o teño dime como facelo mellor, e como - é mellor non facelo. Hoxe falarei do segundo aspecto da actualización masiva: sobre os disparadores.

Por exemplo, nunha mesa na que tes que arranxar algo, colga un gatillo malvado ON UPDATE, transferindo todos os cambios a algúns agregados. E cómpre actualizar todo (iniciar un campo novo, por exemplo) con tanto coidado que estes agregados non se vexan afectados.

Imos desactivar os disparadores!

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

En realidade, iso é todo - todo está colgado.

Porque ALTER TABLE impón Acceso Exclusivo- un peche baixo o que ninguén corre en paralelo, nin sequera un sinxelo SELECT, non poderá ler nada da táboa. É dicir, ata que remate esta transacción, todos os que queiran incluso "só ler" esperarán. E recordamos iso UPDATE temos unha longa...

Apaguemolo rapidamente e despois acendémolo rapidamente!

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

UPDATE ...;

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

Aquí a situación xa é mellor, o tempo de espera é moito menor. Pero só dous problemas estragan toda a beleza:

  • ALTER TABLE agarda por todas as demais operacións sobre a mesa, incluídas as longas SELECT
  • Mentres o gatillo está apagado, "voar" calquera cambio na mesa, nin sequera a nosa. E non entrará nos agregados, aínda que debería. Problema!

Xestión de variables de sesión

Entón, na versión anterior, tropezámonos cun punto fundamental: debemos ensinar dalgunha maneira o disparador a distinguir os "nosos" cambios na táboa de "non os nosos". "Os nosos" sáltanse tal e como están, pero en "non o noso" desencadean. Para iso podes usar variables de sesión.

role_replication_sesión

Lendo manual:

O mecanismo de activación tamén se ve afectado pola variable de configuración role_replication_sesión. Activados sen instrucións adicionais (predeterminado), os disparadores activaranse cando a función de replicación sexa "orixe" (predeterminada) ou "local". Activadores habilitados ao especificar ENABLE REPLICA, funcionará só se modo de sesión actual - "réplica" e activadores habilitados ao especificar ENABLE ALWAYS, funcionará independentemente do modo de replicación actual.

Destacarei especialmente que a configuración non se aplica a todos á vez, xa que ALTER TABLE, pero só coa nosa conexión especial separada. En total, para que ningunha aplicación desencadee o traballo:

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

Condición dentro do gatillo

Pero a opción anterior funciona para todos os disparadores á vez (ou necesitas "alternar" os disparadores con antelación que non queres desactivar). E se necesitamos "desactivar" un disparador específico?

Isto axudaranos variable de sesión "usuario".:

Os nomes dos parámetros de extensión escríbense do seguinte xeito: o nome da extensión seguido dun punto e despois o propio nome do parámetro, de xeito similar aos nomes completos dos obxectos en SQL. Por exemplo: plpgsql.variable_conflict.
Debido a que as opcións fóra do sistema pódense establecer en procesos que non cargan o módulo de extensión adecuado, PostgreSQL acepta valores para calquera nome con dous compoñentes.

Primeiro, finalizamos o disparador, algo así:

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

Por certo, isto pódese facer "con ánimo de lucro", sen bloquear, a través CREATE OR REPLACE para a función de disparo. E despois, na conexión especial, identificamos a "nosa" variable:


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

Coñeces outras formas? Comparte nos comentarios.

Fonte: www.habr.com

Engadir un comentario