Wie deaktiviere ich vorübergehend Trigger in PostgreSQL?

131

Ich lade Daten in großen Mengen und kann alle Trigger-Änderungen im Nachhinein viel billiger als zeilenweise neu berechnen.

Wie kann ich alle Trigger in PostgreSQL vorübergehend deaktivieren?

David Schmitt
quelle

Antworten:

162

Wenn Sie alternativ alle Trigger deaktivieren möchten, nicht nur die in der USER-Tabelle, können Sie Folgendes verwenden:

SET session_replication_role = replica;

Dadurch werden Trigger für die aktuelle Sitzung deaktiviert.

So aktivieren Sie dieselbe Sitzung erneut:

SET session_replication_role = DEFAULT;

Quelle: http://koo.fi/blog/2013/01/08/disable-postgresql-triggers-temporARY/

Zyzof
quelle
2
Genial. Meine Massenlöschung ging von 30 Minuten auf <1 Sekunde :)
Dan Lenski
7
Es ist auch praktisch, dass dieser Befehl keine Einschränkungsauslöser deaktiviert
bartolo-otrit
2
Ich habe die letzte halbe Stunde vergeblich nach einer Möglichkeit gesucht, den Fehler "Verstöße gegen Fremdschlüsseleinschränkungen" in meiner Testumgebung zu umgehen, und genau das ist es!
Amalgovinus
Eine Einschränkung: Gemäß den Laufzeitkonfigurationsdokumenten und den ALTER TABLE-Dokumenten funktioniert dies mit normalen Triggern, jedoch nicht mit denen, die mit ENABLE REPLICAoder festgelegt wurden ENABLE ALWAYS.
Beldaz
Ich bin dran 10.4und es scheint diese obige Aussage zu ignorieren.
Stephane
128

PostgreSQL kennt den ALTER TABLE tblname DISABLE TRIGGER USERBefehl, der zu tun scheint, was ich brauche. Siehe ALTER TABLE .

David Schmitt
quelle
Und wie berechnet man dann "alle Trigger-Modifikationen neu"?
Wojtek Kruszewski
14
Vorsicht bei gleichzeitiger Belastung: ALTER TABLE ... DISABLE TRIGGER USERErfordert eine exklusive Sperre für den Tisch.
Erwin Brandstetter
3
@WojtekKruszewski, ich denke, David meinte, dass er die Änderungen, die durch den Auslöser vorgenommen worden wären, manuell neu berechnen kann, indem er einige Vorkenntnisse verwendet (zum Beispiel, wenn der Auslöser in jeder Zeile dieselbe Änderung vornimmt, was effizienter sein kann von einem einzigen UPDATE behandelt). Ich glaube nicht, dass er meinte, dass Sie dies in jeder Situation tun können.
Rauni Lillemets
1
Die Lösung von @ zyzof ist besser, um alle Trigger zu deaktivieren.
Uthomas
47

Zum Deaktivieren des Auslösers

ALTER TABLE table_name DISABLE TRIGGER trigger_name

Zum Aktivieren des Triggers

ALTER TABLE table_name ENABLE TRIGGER trigger_name
Mise
quelle
Sie können auch "all" dafür verwenden:ALTER TABLE table_name DISABLE TRIGGER all
DenisNovac
8
SET session_replication_role = replica; 

Es funktioniert nicht mit PostgreSQL 9.4 auf meinem Linux-Computer, wenn ich eine Tabelle über den Tabelleneditor in pgAdmin ändere, und funktioniert, wenn ich die Tabelle über eine normale Abfrage ändere. Manuelle Änderungen in der Tabelle pg_trigger funktionieren auch nicht ohne Neustart des Servers, aber dynamische Abfragen wie auf postgresql.nabble.com ENABLE / DISABLE ALL TRIGGERS IN DATABASE funktionieren. Dies kann nützlich sein, wenn Sie eine Abstimmung benötigen.

Wenn Sie beispielsweise Tabellen in einem bestimmten Namespace haben, kann dies sein:

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;

Wenn Sie alle Trigger mit einer bestimmten Triggerfunktion deaktivieren möchten, kann dies sein:

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;

PostgreSQL-Dokumentation für Systemkataloge


Es gibt weitere Steuerungsoptionen für den Trigger-Zündvorgang:

ALTER TABLE ... REPLICA TRIGGER AKTIVIEREN ... - Der Trigger wird nur im Replikationsmodus ausgelöst.

ALTER TABLE ... IMMER TRIGGER AKTIVIEREN ... - Trigger wird immer (offensichtlich) ausgelöst

Bartolo-Otrit
quelle
7

Sie können Trigger auch in pgAdmin (III) deaktivieren:

  1. Finde deinen Tisch
  2. Erweitern Sie das +
  3. Finden Sie Ihren Trigger in Trigger
  4. Klicken Sie mit der rechten Maustaste und deaktivieren Sie "Trigger aktiviert?"
Neil McGuigan
quelle
4
SET session_replication_role = replica;  

auch dosent Arbeit für mich in Postgres 9.1. Ich benutze die beiden von Bartolo-Otrit beschriebenen Funktionen mit einigen Modifikationen. Ich habe die erste Funktion so geändert, dass sie für mich funktioniert, da der Namespace oder das Schema vorhanden sein müssen, um die Tabelle korrekt zu identifizieren. Der neue Code lautet:

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;

dann mache ich einfach eine Auswahlabfrage für jedes Schema:

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