Как временно отключить триггеры в PostgreSQL?

132

Я загружаю данные массово и могу повторно вычислить все модификации триггеров постфактум с гораздо меньшими затратами, чем построчно.

Как временно отключить все триггеры в PostgreSQL?

Дэвид Шмитт
источник

Ответы:

164

В качестве альтернативы, если вы хотите отключить все триггеры, а не только те, что находятся в таблице USER, вы можете использовать:

SET session_replication_role = replica;

Это отключает триггеры для текущего сеанса.

Чтобы повторно включить тот же сеанс:

SET session_replication_role = DEFAULT;

Источник: http://koo.fi/blog/2013/01/08/disable-postgresql-triggers-tempoporary/

zyzof
источник
2
Потрясающие. У меня массовое удаление увеличилось с 30 минут до <1 секунды :)
Дэн Ленски
7
Также удобно, что эта команда не отключает триггеры ограничений
bartolo-otrit
2
Последние полчаса я тщетно искал способ обойти ошибку «нарушает ограничения внешнего ключа» в моей тестовой среде, и вот именно!
Амальговинус
Одно предостережение: согласно документам конфигурации времени выполнения и документам ALTER TABLE это будет работать с обычными триггерами, но не с теми, которые установлены с помощью ENABLE REPLICAили ENABLE ALWAYS.
beldaz 07
Я продолжаю 10.4и, кажется, игнорирую это заявление выше.
Стефан
129

PostgreSQL знает ALTER TABLE tblname DISABLE TRIGGER USERкоманду, которая, кажется, делает то, что мне нужно. Смотрите ALTER TABLE .

Дэвид Шмитт
источник
А как потом «пересчитать все модификации триггера»?
Wojtek Kruszewski
15
Осторожно с одновременной загрузкой: ALTER TABLE ... DISABLE TRIGGER USERтребуется монопольная блокировка таблицы.
Эрвин Брандштеттер,
3
@WojtekKruszewski, я думаю, что Дэвид имел в виду, что он может вручную пересчитать изменения, которые были бы внесены триггером, используя некоторые предварительные знания (например, если триггер внесет одно и то же изменение в каждую строку, что может быть более эффективно обрабатывается одним ОБНОВЛЕНИЕМ). Я не думаю, что Он имел в виду, что Вы можете делать это в любой ситуации.
Rauni Lillemets
1
Решение @zyzof лучше для отключения всех триггеров.
uthomas 01
48

Для отключения триггера

ALTER TABLE table_name DISABLE TRIGGER trigger_name

Для включения триггера

ALTER TABLE table_name ENABLE TRIGGER trigger_name
Mise
источник
1
Вы также можете использовать для этого «все»:ALTER TABLE table_name DISABLE TRIGGER all
DenisNovac
8
SET session_replication_role = replica; 

Он не работает с PostgreSQL 9.4 на моем компьютере с Linux, если я изменяю таблицу через редактор таблиц в pgAdmin, и работает, если я изменяю таблицу с помощью обычного запроса. Ручные изменения в таблице pg_trigger также не работают без перезапуска сервера, но работает динамический запрос, как на postgresql.nabble.com ВКЛЮЧИТЬ / ОТКЛЮЧИТЬ ВСЕ ТРИГГЕРЫ В БАЗЕ ДАННЫХ . Это может быть полезно, когда вам нужна настройка.

Например, если у вас есть таблицы в определенном пространстве имен, это может быть:

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;

Если вы хотите отключить все триггеры с определенной функцией триггера, это может быть:

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 для системных каталогов


Есть и другие варианты управления процессом срабатывания спускового крючка:

ALTER TABLE ... ENABLE REPLICA TRIGGER ... - триггер сработает только в режиме реплики.

ALTER TABLE ... ENABLE ALWAYS TRIGGER ... - триггер будет срабатывать всегда (очевидно)

Бартоло-otrit
источник
7

Вы также можете отключить триггеры в pgAdmin (III):

  1. Найдите свой стол
  2. Разверните +
  3. Найдите свой триггер в триггерах
  4. Щелкните правой кнопкой мыши, снимите флажок "Триггер включен?"
Нил Макгиган
источник
4
SET session_replication_role = replica;  

Также у меня работа dosent в Postgres 9.1. Я использую две функции, описанные bartolo-otrit с некоторыми изменениями. Я изменил первую функцию, чтобы она работала для меня, потому что для правильной идентификации таблицы должно присутствовать пространство имен или схема. Новый код:

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;

то я просто выполняю запрос выбора для каждой схемы:

SELECT disable_triggers(true,'public');
SELECT disable_triggers(true,'Adempiere');
Сами Чохен
источник