在 PostgreSQL 中进行 DROP 时,避免引用表上的独占访问锁

2024-05-08

为什么在 PostgreSQL 中删除表需要ACCESS EXCLUSIVE锁定任何引用的表?我怎样才能将其减少到ACCESS SHARED锁还是根本不锁?即有没有办法在不锁定引用表的情况下删除关系?

我在文档中找不到任何提及需要哪些锁,但是除非我在并发操作期间删除多个表时显式地以正确的顺序获取锁,否则我可以在日志中看到等待 AccessExclusiveLock 的死锁,并获取此限制性删除表时,对常用引用表的锁定会导致其他进程出现短暂延迟。

澄清,

CREATE TABLE base (
    id SERIAL,
    PRIMARY KEY (id)
);
CREATE TABLE main (
    id SERIAL,
    base_id INT,
    PRIMARY KEY (id),
    CONSTRAINT fk_main_base (base_id)
        REFERENCES base (id)
        ON DELETE CASCADE ON UPDATE CASCADE
);
DROP TABLE main; -- why does this need to lock base?

对于任何通过谷歌搜索并试图理解为什么他们的删除表(或删除外键或添加外键)长期卡住的人:

PostgreSQL(我查看了9.4到13版本)外键约束实际上是使用外键两端的触发器来实现的.

如果您有一个company表(id作为主键)和一个bank_account表(id作为主键,company_id作为指向company.id的外键),那么bank_account表上实际上有2个触发器,company上也有2个触发器桌子。

table_name timing trigger_name function_name
bank_account AFTER UPDATE RI_ConstraintTrigger_c_1515961 RI_FKey_check_upd
bank_account AFTER INSERT RI_ConstraintTrigger_c_1515960 RI_FKey_check_ins
company AFTER UPDATE RI_ConstraintTrigger_a_1515959 RI_FKey_noaction_upd
company AFTER DELETE RI_ConstraintTrigger_a_1515958 RI_FKey_noaction_del

这些触发器的初始创建(当创建外键时)需要在这些表上使用 SHARE ROW EXCLUSIVE 锁(在版本 9.4 及更早版本中它曾经是 ACCESS EXCLUSIVE 锁)。该锁不会与“数据读取锁”冲突,但会与所有其他锁冲突,例如对公司表的简单插入/更新/删除。

删除这些触发器(当删除外键或整个表时)需要这些表上的 ACCESS EXCLUSIVE 锁。该锁与其他所有锁冲突!

因此,想象一个场景,您有一个正在运行的事务 A,它首先从公司表中执行了一个简单的 SELECT(导致它持有公司表的 ACCESS SHARE 锁,直到事务提交或回滚),现在正在为公司做一些其他工作3分钟。您尝试删除事务B中的bank_account表。这需要ACCESS EXCLUSIVE锁,该锁需要等待ACCESS SHARE锁首先被释放。 除此之外,想要访问公司表(只是 SELECT,或者可能是 INSERT/UPDATE/DELETE)的所有其他事务都将排队等待 ACCESS EXCLUSIVE 锁,而该锁正在等待 ACCESS SHARE 锁。

长时间运行的事务和 DDL 更改需要精细处理。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 PostgreSQL 中进行 DROP 时,避免引用表上的独占访问锁 的相关文章

随机推荐