我正在尝试删除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
:
外键约束在 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 TRIGGER
onaccount
必须在持有锁的当前活动事务后面排队account
,并且所有后续事务都必须在 后面排队DROP TRIGGER
,这就是您所观察到的。
您必须找到一个没有长时间运行的事务涉及的时间account
,然后您DROP TABLE
将快速完成而不阻塞其他会话。
旁注:选择bigint
而不是integer
人工主键列。
归档时间: |
|
查看次数: |
2502 次 |
最近记录: |