迟早,许多人都需要大规模修复表条目中的某些内容。我已经告诉过如何做得更好,以及如何做-最好不要做。今天,我将讨论大规模更新触发触发器的第二个方面。例如,在需要修复某些东西的桌子上,一个邪恶的触发器挂起ON UPDATE
,将所有更改转移到某些聚合中。并且您需要非常仔细地更新所有内容(例如,初始化一个新字段),以使这些单元不受影响。让我们关闭触发器!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
UPDATE ...;
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;
实际上,仅此而已- 一切都已悬而未决。因为它ALTER TABLE
强加了AccessExclusive锁,在该锁下,任何并行运行的人,即使是简单的SELECT
,都无法从表中读取任何内容。也就是说,在此事务完成之前,所有想“阅读”的人都将等待。而且我们还记得UPDATE
我们在做...让我们快速关闭它,然后迅速打开它!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
COMMIT;
UPDATE ...;
BEGIN;
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;
这里的情况更好,等待时间要短得多。但是只有两个问题破坏了所有的美丽:ALTER TABLE
他等待桌上的所有其他操作,包括长时间 SELECT
- 触发器关闭时,表中的任何更改都会(而不是我们的)飞行。嗯,尽管应该,它也不会进入单元。麻烦!
会话变量管理
因此,在以前的版本中,我们偶然发现了一个关键点-我们需要以某种方式教导触发器以区分表中的“我们的”更改与“非我们的”更改。跳过“我们的”,但不“我们的”-触发。您可以为此使用会话变量。session_replication_role
阅读手册:触发器变量还受session_replication_role配置变量的影响。当复制角色为“原始”(默认)或“本地”时,将触发没有其他指令(默认)的触发器。指示启用的触发器ENABLE REPLICA
仅在当前会话模式为“副本”时ENABLE ALWAYS
才会触发,并且指示启用的触发器无论当前复制模式如何都将触发。
我强调,该配置不能一次全部应用ALTER TABLE
,而是仅应用于我们单独的特殊连接。总计,因此没有应用程序会触发火灾:SET session_replication_role = replica;
UPDATE ...;
SET session_replication_role = DEFAULT;
触发器内部条件
但是上述选项可同时适用于所有触发器(或者您需要预先“触发”不想禁用的触发器)。如果我们需要“关闭”一个特定的触发器?“用户”会话变量将帮助我们:扩展参数名称的编写方式如下:扩展名称,句点,然后是参数名称本身,例如SQL中对象的全名。例如:plpgsql.variable_conflict。
由于可以在不加载相应扩展模块的进程中设置非系统参数,因此PostgreSQL接受具有两个组件的任何名称的值。
首先,修改触发器,如下所示:BEGIN
IF current_setting('mycfg.my_table_convert_process') = 'TRUE' THEN
IF TG_OP IN ('INSERT', 'UPDATE') THEN
RETURN NEW;
ELSE
RETURN OLD;
END IF;
END IF;
...
顺便说一下,这可以“无偿地”完成,没有锁,直到CREATE OR REPLACE
触发功能。然后在特殊连接中,我们将“我们的”变量作为公鸡:
SET mycfg.my_table_convert_process = 'TRUE';
UPDATE ...;
SET mycfg.my_table_convert_process = '';
你知道其他方式吗?分享评论。