PostgreSQL 10:删除外键锁选择

Ale*_*aru 2 postgresql

我正在尝试删除incoming每秒有 100 个事务的繁忙数据库中的一个表(称为 )。表本身是空的(truncate table之前执行过)。如果我尝试在其他各种正在等待的表上执行drop table incoming大量事务drop table显然不好。

我开始一一删除索引、约束和列,以确定是什么阻止了表删除,并找到了导致锁定的外键约束。这是“最终”incoming表架构:

create table incoming
(
    account_id integer
        constraint incoming_account_id_fkey
            references account
);
Run Code Online (Sandbox Code Playgroud)

从被阻止的查询来看(ticket以下表为例),看起来并不是account表查询被阻止,而是在一个繁忙的表上的查询ticket,该表具有该表的外键account。为什么删除 FK inincoming块查询ticket

这是 3 个表的概要:

  • incoming- 这是我要删除的外键所在的位置(参见下面的架构)。
  • account- 外键参考表。
  • ticket- 具有外键约束的繁忙表(选择、插入、更新等)account

我尝试做的事情:

我尝试禁用 table: 上的触发器ALTER TABLE incoming DISABLE TRIGGER ALL;并设置 FK DEFERRABLE: ALTER TABLE incoming ALTER CONSTRAINT incoming_account_id_fkey DEFERRABLE;。没有帮助。

这是以下的输出pg_constraint

SELECT conname, conindid::regclass, confrelid::regclass, * FROM pg_constraint WHERE conrelid = 'incoming'::regclass

pg_constraint 输出

Lau*_*lbe 6

外键约束在 PostgreSQL 中作为系统触发器实现。

此查询显示外键约束背后的触发器:

SELECT t.tgrelid::regclass AS table_name,
       t.tgname AS trigger_name,
       concat(
          CASE t.tgtype & 66 WHEN 2 THEN 'BEFORE ' WHEN 64 THEN 'INSTEAD OF ' ELSE 'AFTER ' END,
          CASE WHEN t.tgtype & 4 > 0 THEN 'INSERT' END,
          CASE WHEN t.tgtype & 8 > 0 THEN 'DELETE' END,
          CASE WHEN t.tgtype & 16 > 0 THEN 'UPDATE' END
       ) AS fires,
       f.proname AS trigger_function
FROM pg_trigger AS t
   JOIN pg_proc AS f ON t.tgfoid = f.oid
   JOIN pg_constraint AS c ON t.tgconstraint = c.oid
WHERE c.conname = 'incoming_account_id_fkey';

 table_name |         trigger_name         |     fires     |   trigger_function   
------------+------------------------------+---------------+----------------------
 account    | RI_ConstraintTrigger_a_62074 | AFTER DELETE  | RI_FKey_noaction_del
 account    | RI_ConstraintTrigger_a_62075 | AFTER UPDATE  | RI_FKey_noaction_upd
 incoming   | RI_ConstraintTrigger_c_62076 | AFTER INSERT  | RI_FKey_check_ins
 incoming   | RI_ConstraintTrigger_c_62077 | AFTER UPDATE  | RI_FKey_check_upd
(4 rows)
Run Code Online (Sandbox Code Playgroud)

您会看到其中两个触发器是在目标表 上定义的account

如果删除表incoming,也会删除外键约束,从而删除触发器account,这需要短暂ACCESS EXCLUSIVE锁定account

这不应该造成破坏,但您似乎正在运行涉及account. 现在DROP TRIGGERonaccount必须在持有锁的当前活动事务后面排队account,并且所有后续事务都必须在 后面排队DROP TRIGGER,这就是您所观察到的。

您必须找到一个没有长时间运行的事务涉及的时间account,然后您DROP TABLE将快速完成而不阻塞其他会话。

旁注:选择bigint而不是integer人工主键列。