¿Cómo deshabilito temporalmente los activadores en PostgreSQL?

131

Estoy cargando datos de forma masiva y puedo volver a calcular todas las modificaciones de activación de forma mucho más económica después del hecho que fila por fila.

¿Cómo puedo desactivar temporalmente todos los desencadenantes en PostgreSQL?

David Schmitt
fuente

Respuestas:

163

Alternativamente, si desea deshabilitar todos los desencadenantes, no solo los de la tabla USER, puede usar:

SET session_replication_role = replica;

Esto desactiva los disparadores para la sesión actual.

Para volver a habilitar para la misma sesión:

SET session_replication_role = DEFAULT;

Fuente: http://koo.fi/blog/2013/01/08/disable-postgresql-triggers-tempomporary/

zyzof
fuente
2
Increíble. Hice que mi eliminación masiva fuera de 30 minutos a <1 segundo :)
Dan Lenski el
77
También es útil que este comando no deshabilite los activadores de restricción
bartolo-otrit
2
He pasado la última media hora buscando en vano una forma de evitar el error "viola las restricciones de clave externa" en mi entorno de prueba, ¡y esto es exactamente!
Amalgovinus
Una advertencia: de acuerdo con los documentos de configuración de tiempo de ejecución y los documentos ALTER TABLE, esto funcionará con desencadenantes normales, pero no con los establecidos con ENABLE REPLICAo ENABLE ALWAYS.
beldaz
Estoy encendido 10.4y parece ignorar esta declaración anterior.
Stephane
129

PostgreSQL conoce el ALTER TABLE tblname DISABLE TRIGGER USERcomando, que parece hacer lo que necesito. Ver ALTER TABLE .

David Schmitt
fuente
Y luego, ¿cómo "recalcula todas las modificaciones de disparo"?
Wojtek Kruszewski
15
Cuidado con la carga concurrente: ALTER TABLE ... DISABLE TRIGGER USERrequiere un bloqueo exclusivo en la mesa.
Erwin Brandstetter
3
@WojtekKruszewski, creo que David quiso decir que puede volver a calcular los cambios manualmente que habría hecho por disparador, utilizando algunos conocimientos previos (por ejemplo, si el disparador hará el mismo cambio en cada fila, lo que puede ser más eficiente manejado por una sola ACTUALIZACIÓN). No creo que haya querido decir que puedes hacer esto en cada situación.
Rauni Lillemets
1
La solución de @zyzof es mejor para deshabilitar todos los desencadenantes.
uthomas
48

Para desactivar el disparador

ALTER TABLE table_name DISABLE TRIGGER trigger_name

Para habilitar el disparador

ALTER TABLE table_name ENABLE TRIGGER trigger_name
Mise
fuente
1
También puede usar "todos" para esto:ALTER TABLE table_name DISABLE TRIGGER all
DenisNovac
8
SET session_replication_role = replica; 

No funciona con PostgreSQL 9.4 en mi máquina Linux si cambio una tabla a través del editor de tablas en pgAdmin y funciona si cambio la tabla a través de una consulta ordinaria. Los cambios manuales en la tabla pg_trigger tampoco funcionan sin el reinicio del servidor, pero la consulta dinámica como en postgresql.nabble.com ACTIVA / DESACTIVA TODOS LOS DISPARADORES EN LA BASE DE DATOS funciona. Podría ser útil cuando necesita algo de ajuste.

Por ejemplo, si tiene tablas en un espacio de nombres en particular, podría ser:

create or replace function disable_triggers(a boolean, nsp character varying) returns void as
$$
declare 
act character varying;
r record;
begin
    if(a is true) then
        act = 'disable';
    else
        act = 'enable';
    end if;

    for r in select c.relname from pg_namespace n
        join pg_class c on c.relnamespace = n.oid and c.relhastriggers = true
        where n.nspname = nsp
    loop
        execute format('alter table %I %s trigger all', r.relname, act); 
    end loop;
end;
$$
language plpgsql;

Si desea deshabilitar todos los disparadores con cierta función de disparo, podría ser:

create or replace function disable_trigger_func(a boolean, f character varying) returns void as
$$
declare 
act character varying;
r record;
begin
    if(a is true) then
        act = 'disable';
    else
        act = 'enable';
    end if;

    for r in select c.relname from pg_proc p 
        join pg_trigger t on t.tgfoid = p.oid
        join pg_class c on c.oid = t.tgrelid
        where p.proname = f
    loop
        execute format('alter table %I %s trigger all', r.relname, act); 
    end loop;
end;
$$
language plpgsql;

Documentación de PostgreSQL para catálogos de sistemas


Hay otras opciones de control del proceso de disparo del disparador:

ALTER TABLE ... ENABLE REPLICA TRIGGER ... - el disparador se disparará solo en modo réplica.

ALTER TABLE ... HABILITAR SIEMPRE GATILLO ... - el gatillo se disparará siempre (obviamente)

Bartolo-otrit
fuente
7

También puede deshabilitar los desencadenantes en pgAdmin (III):

  1. Encuentra tu mesa
  2. Expande el +
  3. Encuentra tu disparador en Triggers
  4. Haga clic derecho, desmarque "¿Activador activado?"
Neil McGuigan
fuente
4
SET session_replication_role = replica;  

También no me funciona en Postgres 9.1. Yo uso las dos funciones descritas por Bartolo-otrit con alguna modificación. Modifiqué la primera función para que funcione para mí porque el espacio de nombres o el esquema deben estar presentes para identificar la tabla correctamente. El nuevo código es:

CREATE OR REPLACE FUNCTION disable_triggers(a boolean, nsp character varying)
  RETURNS void AS
$BODY$
declare 
act character varying;
r record;
begin
    if(a is true) then
        act = 'disable';
    else
        act = 'enable';
    end if;

    for r in select c.relname from pg_namespace n
        join pg_class c on c.relnamespace = n.oid and c.relhastriggers = true
        where n.nspname = nsp
    loop
        execute format('alter table %I.%I %s trigger all', nsp,r.relname, act); 
    end loop;
end;
$BODY$
  LANGUAGE plpgsql VOLATILE
  COST 100;
ALTER FUNCTION disable_triggers(boolean, character varying)
  OWNER TO postgres;

entonces simplemente hago una consulta de selección para cada esquema:

SELECT disable_triggers(true,'public');
SELECT disable_triggers(true,'Adempiere');
Samih Chouhen
fuente