迟早,许多人都需要大量修复表记录中的某些内容。 我已经
例如,在您需要修复某些东西的桌子上,一个邪恶的触发器挂起 ON UPDATE
,将所有更改转移到某些聚合。 并且您需要非常小心地更新所有内容(例如初始化一个新字段),以免这些聚合受到影响。
让我们禁用触发器!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
UPDATE ...; -- тут долго-долго
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;
其实,仅此而已—— 一切都挂了.
因为 ALTER TABLE
施加 访问独家- 一个没有人并行运行的锁,即使是一个简单的锁 SELECT
, 将无法从表中读取任何内容。 也就是说,在这个交易结束之前,每个想要“只读”的人都会等待。 我们记得 UPDATE
我们有很长的...
让我们快速关闭它,然后快速打开它!
BEGIN;
ALTER TABLE ... DISABLE TRIGGER ...;
COMMIT;
UPDATE ...;
BEGIN;
ALTER TABLE ... ENABLE TRIGGER ...;
COMMIT;
这里的情况已经好了很多,等待的时间也少了很多。 但只有两个问题破坏了所有的美丽:
ALTER TABLE
本身等待表上的所有其他操作,包括长操作SELECT
- 当触发器关闭时 “飞过”任何变化 在桌子上,甚至不是我们的。 它不会进入聚合,尽管它应该。 麻烦!
管理会话变量
因此,在之前的版本中,我们偶然发现了一个基本点——我们需要以某种方式教会触发器区分表中“我们的”更改和“不是我们的”更改。 “我们的”按原样被跳过,但在“不是我们的”时它们被触发。 为此,您可以使用
会话复制角色
我们读了
触发机制也受配置变量的影响
会话复制角色 . 在没有额外说明的情况下启用(默认),当复制角色是“源”(默认)或“本地”时,触发器将触发。 通过指定启用触发器ENABLE REPLICA
, 只有当 当前会话模式 - “副本”,并通过指定启用触发器ENABLE ALWAYS
, 无论当前的复制模式如何,都将起作用。
我要特别强调的是,该设置不适用于 all-all at once,因为 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 = ''; -- вернули в исходное состояние
你知道其他方法吗? 在评论中分享。
来源: habr.com