如何在 PostgreSQL 中临时禁用触发器?

Posted

技术标签:

【中文标题】如何在 PostgreSQL 中临时禁用触发器?【英文标题】:How do I temporarily disable triggers in PostgreSQL? 【发布时间】:2011-04-25 22:18:44 【问题描述】:

我正在批量加载数据,并且可以在事后重新计算所有触发器修改,这比逐行计算要便宜得多。

如何暂时禁用 PostgreSQL 中的所有触发器?

【问题讨论】:

【参考方案1】:

用于禁用触发器

ALTER TABLE table_name DISABLE TRIGGER trigger_name

用于启用触发器

ALTER TABLE table_name ENABLE TRIGGER trigger_name

【讨论】:

您也可以为此使用“all”:ALTER TABLE table_name DISABLE TRIGGER all【参考方案2】:
SET session_replication_role = replica;  

在 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');

【讨论】:

【参考方案3】:
SET session_replication_role = replica; 

如果我通过 pgAdmin 中的表编辑器更改表,它不适用于我的 Linux 机器上的 PostgreSQL 9.4,如果我通过普通查询更改表,则它可以工作。 pg_trigger 表中的手动更改在没有服务器重启的情况下也不起作用,但是像postgresql.nabble.com ENABLE / DISABLE ALL TRIGGERS IN DATABASE 这样的动态查询可以工作。当您需要进行一些调整时,它可能会很有用。

例如,如果您在特定命名空间中有表,则可能是:

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;

system catalogs 的 PostgreSQL 文档


触发器触发过程还有另一个控制选项:

ALTER TABLE ... ENABLE REPLICA TRIGGER ... - 触发器仅在副本模式下触发。

ALTER TABLE ... ENABLE ALWAYS TRIGGER ... - 触发器将始终触发(显然)

【讨论】:

【参考方案4】:

您还可以在 pgAdmin (III) 中禁用触发器:

    找到您的餐桌 展开+ 在触发器中找到您的触发器 右键单击,取消选中“触发器已启用?”

【讨论】:

【参考方案5】:

或者,如果您想禁用所有触发器,而不仅仅是 USER 表上的触发器,您可以使用:

SET session_replication_role = replica;

这会禁用当前会话的触发器。

为同一会话重新启用:

SET session_replication_role = DEFAULT;

来源:http://koo.fi/blog/2013/01/08/disable-postgresql-triggers-temporarily/

【讨论】:

太棒了。让我的大规模删除从 30 分钟缩短到 这个命令不禁用约束触发器也很方便 我花了半个小时徒劳地寻找一种方法来绕过我的测试环境中的“违反外键约束”错误,就是这样! 一个警告:根据runtime config docs 和ALTER TABLE docs,这将适用于普通触发器,但不适用于使用ENABLE REPLICAENABLE ALWAYS 设置的触发器。 我在10.4,它似乎忽略了上述声明。【参考方案6】:

PostgreSQL 知道ALTER TABLE tblname DISABLE TRIGGER USER 命令,这似乎可以满足我的需要。见ALTER TABLE。

【讨论】:

那你如何“重新计算所有触发器修改”? 小心并发加载:ALTER TABLE ... DISABLE TRIGGER USER 需要对表进行排他锁。 @WojtekKruszewski,我认为大卫的意思是他可以使用一些先验知识手动重新计算触发器会完成的更改(例如,如果触发器将在每行,可以通过单个 UPDATE 更有效地处理)。我不认为他的意思是你可以在任何情况下都这样做。 @zyzof 的解决方案更适合禁用所有触发器。

以上是关于如何在 PostgreSQL 中临时禁用触发器?的主要内容,如果未能解决你的问题,请参考以下文章

mysql临时禁用触发器

用于禁用/启用触发所有的 Postgresql 权限

在 PostgreSQL 中的表上禁用 DELETE?

如何在 PostgreSQL 中运行临时脚本?

我可以暂时禁用 oracle 存储过程中的触发器吗?

如何在 PostgreSQL 中创建临时函数?