如何仅在一个事务中禁用PostgreSQL触发器?

gor*_*ori 7 database postgresql triggers postgresql-9.5

我需要临时禁用一个事务中的一个postgreSQL触发器,但没有硬件锁定表,有人知道是否可能

这样的事情,但没有锁定表和禁止在此事务之外的触发器

BEGIN TRANSACTION;

  ALTER TABLE foo DISABLE TRIGGER bar;

  -- DO SOME UPDATES ON foo
  UPDATE foo set field = 'value' where field = 'test';

  ALTER TABLE foo ENABLE TRIGGER bar;

COMMIT;
Run Code Online (Sandbox Code Playgroud)

Ale*_*ore 10

我遇到了同样的问题,并找到了一种聪明而干净的方法来解决它。

\n

首先,如果当前正在执行触发器,则不能禁用触发器内的触发器。这是我的场景 - 我由于插入到表中而插入到表中 - 否则会导致触发器无限循环。

\n

我解决这个问题的方法是在混合中添加一个本地参数变量,该变量本质上充当全局变量,当触发器已经被使用时,它将禁用触发器的进一步调用。

\n

为此,请在触发器函数的最开始添加以下代码:

\n

SET LOCAL your.variable_name to 'TRUE';

\n

然后(假设您正在使用 pg \xe2\x89\xa5 9.6)您只需将以下行添加到您的CREATE TRIGGER

\n

WHEN (current_setting('your.variable_name', 't') <> 'TRUE')

\n

我还没有做过任何基准测试,但根据我之前的经验,我希望它的性能非常好。

\n

更新:

\n

我已经在一个高度活跃的数据仓库中使用这种方法好几年了,现在默认情况下在我的所有触发器(可能有 50 个)上设置了它。我已经将代码形式化为:

\n
CREATE OR REPLACE FUNCTION trigger_state(\n    IN setting_name TEXT\n) RETURNS BOOLEAN AS\n$$\nBEGIN\n\nRETURN coalesce(NOT upper(current_setting(setting_name, TRUE)) = 'DISABLED',TRUE);\n\nEND\n$$\nLANGUAGE plpgsql\nSTABLE\n;\n
Run Code Online (Sandbox Code Playgroud)\n

并像这样使用它:

\n
CREATE TRIGGER some_trigger\n    BEFORE INSERT\n    ON some_table\n    FOR EACH ROW\n    WHEN (\n            trigger_state('some_domain_name.trigger_state.some_trigger')\n        AND OLD.some_column IS DISTINCT FROM NEW.some_column\n        )\n    EXECUTE FUNCTION some_trg_funct()\n;\n\n\n
Run Code Online (Sandbox Code Playgroud)\n

要禁用触发器(出于任何原因),无论是在代码还是命令行中,只需:

\n

SET "some_domain_name.trigger_state.some_trigger" = 'DISABLED';

\n

正如您所期望的语法一样,这适用于事务、会话等SET。它不受锁定或类似情况的影响,并且在当前会话/范围内立即生效。

\n

注意:然而,其影响在全球范围内是不可预测的(尤其是在短期内)。如果您需要全局禁用触发器,那么最好的方法是使用上面提到的规范方法。

\n

不管怎样,它对我来说非常有帮助。我除了成功之外一无所有——至少就我后来能够讲述的大量交易而言是这样。

\n

  • 要禁用触发器链接,您可以查看堆栈深度 - 查看 pg_trigger_depth() 函数 (2认同)

Wal*_*zak 8

您可以禁用此表中的所有触发器。它应该是这样的:

ALTER TABLE tblname DISABLE TRIGGER USER;
Your SQL;
ALTER TABLE tblname ENABLE TRIGGER USER;
Run Code Online (Sandbox Code Playgroud)

要禁用单个触发器,请使用以下命令:

ALTER TABLE tblname DISABLE TRIGGER trigger_name;
Your SQL;
ALTER TABLE tblname ENABLE TRIGGER trigger_name;
Run Code Online (Sandbox Code Playgroud)

您可以在文档中阅读有关ALTER TABLE 的更多信息。

  • 是的,但我希望它仅在一个 sql 事务中被禁用,并且不想在禁用触发器时阻塞表。DISABLE TRIGGER : 在事务中硬锁表 (4认同)
  • 这并不能回答 gori 的问题。他和我自己需要在不锁定桌子的情况下禁用触发器。假设我的交易需要 60 秒并且触发器被禁用。该表将被锁定,这在生产中是不可接受的。 (3认同)

Dav*_*ave 8

要临时禁用PostgreSQL会话中的所有触发器,请使用以下命令:

SET session_replication_role = replica;
Run Code Online (Sandbox Code Playgroud)

这将仅禁用当前数据库会话的所有触发器.对于批量操作很有用,但请记住要小心保持数据库的一致性.

要重新启用:

SET session_replication_role = DEFAULT;
Run Code Online (Sandbox Code Playgroud)

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

  • 回答我自己的问题似乎没有 (2认同)