在删除PostgreSQL时避免引用表上的独占访问锁

在删除PostgreSQL时避免引用表上的独占访问锁,postgresql,database-deadlocks,drop-table,Postgresql,Database Deadlocks,Drop Table,为什么在PostgreSQL中删除表需要对任何引用的表使用ACCESS EXCLUSIVE锁?我如何才能将其减少为访问共享锁定或根本不锁定?i、 是否有一种方法可以在不锁定引用表的情况下删除关系 我在文档中找不到任何关于需要哪些锁的说明,但除非我在并发操作期间删除多个表时以正确的顺序显式获得锁,否则我可以在日志中看到等待AccessExclusiveLock的死锁,在删除表时,在常用引用表上获取这种限制性锁会导致其他进程的短暂延迟 澄清一下, CREATE TABLE base ( id

为什么在PostgreSQL中删除表需要对任何引用的表使用
ACCESS EXCLUSIVE
锁?我如何才能将其减少为
访问共享
锁定或根本不锁定?i、 是否有一种方法可以在不锁定引用表的情况下删除关系

我在文档中找不到任何关于需要哪些锁的说明,但除非我在并发操作期间删除多个表时以正确的顺序显式获得锁,否则我可以在日志中看到等待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?

我认为DDL只为了简单而锁定它所涉及的所有内容——无论如何,在正常操作期间,您都不应该运行DDL,因为它不涉及临时表


为避免死锁,您可以使用建议锁:

start transaction;
select pg_advisory_xact_lock(0);
drop table main;
commit;
这将确保只有一个客户机同时运行涉及引用表的DDL,所以获取其他锁的顺序无关紧要


您可以通过先删除外键来避免长时间锁定表:

start transaction;
select pg_advisory_xact_lock(0);
alter table main drop constraint fk_main_base;
commit;
start transaction;
drop table main;
commit;

这仍然需要以独占方式锁定
base
,但锁定时间要短得多。

对于任何通过谷歌搜索并试图了解其删除表(或删除外键或添加外键)为何被长时间卡住的人:

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

如果您有一个公司表(id作为主键)和一个银行帐户表(id作为主键,公司id作为指向company.id的外键),那么实际上银行帐户表上有两个触发器,公司表上也有两个触发器

表名称 时机 触发器名称 函数名 银行账户 更新后 RI_ConstraintTrigger_c_1515961 检查 银行账户 插入后 RI_ConstraintTrigger_c_1515960 登记入住 公司 更新后 RI_ConstraintTrigger_a_1515959 我没有行动 公司 删除后 RI_ConstraintTrigger_a_1515958 我没有行动
你希望发生什么?你正试图从一家繁忙的餐厅搬走家具,但人们仍在用餐的一半,他们应该支付什么费用?一半饭?全餐?只有他们消耗的那部分?@wildplasser我不理解你的比喻;我不是说要删除的表上的锁,而是它引用的表上的锁。被引用的表不应该关心是否正在进行删除操作——它的数据不会被操作更改。它根本不需要做任何事情。@wildplasser看我的例子我明白了。我仍然不清楚您为什么要删除并(可能)重新创建表。顺便说一句:目录上的酸是硬的;可能是postgres在这里过于防御。@wildplasser这些表没有被重新创建。这些表格用于确保客户隔离(如项目1数据等)。为此,我们正在迁移到使用模式(我们可以简单地复制共享信息),但由于我们仍处于从MySQL迁移的过程中,我们还无法进行更改。当我们归档死掉的项目时,表会被删除,但更重要的是,在集成测试期间,我们会快速创建和销毁项目,以确保其测试环境的隔离。“回滚时,另一个会话将失败”:我认为这是一种对您来说很明显的可能性,但不知何故我忽略了:
DROP TABLE
事务可能回滚。这就解释了为什么不能立即删除和忘记约束。我仍然不确定锁的类型
altertable
UPDATE
是需要锁的好例子,但我相信通过
accessshared
锁可以避免这两种情况。有没有一个例子,你能想到在哪里
ACCESS SHARED
是不够的,或者只是postgres像你最初建议的那样过于防御?经验法则:不要将DDL和DML混用。(注意:在进行DDL时,请退出其他会话。出于测试目的,这不会导致问题)是的:这种课程锁定过于保守;有原因的。要短多少?X秒有限制吗?还是只少10%?我问这个问题是因为知道多长时间能让你在网上做这件事和不做这件事有很大的区别。请不要添加多个问题。回答最好的一个,并将其余的标记为重复项。看,它不会让我将另一个标记为重复,因为这里的这一个还没有被接受的答案。但是我从另一个问题中删除了我的答案。现在它有了一个被接受的答案;)-这是很好的信息;谢谢你回答一个6岁的问题!
start transaction;
select pg_advisory_xact_lock(0);
drop table main;
commit;
start transaction;
select pg_advisory_xact_lock(0);
alter table main drop constraint fk_main_base;
commit;
start transaction;
drop table main;
commit;