Postgres - 更新列时的死锁,该列也是where子句的一部分

时间:2016-09-29 11:45:55

标签: sql postgresql

我的同事在工作,我想知道在更新期间,如果在where子句中使用相同列时正在更新列,则可能会出现死锁。

例如:

UPDATE EMPLOYEES
SET DEPT_ID = NULL
WHERE DEPT_ID = 13;

因此,如果表EMPLOYEES包含大约一百万条记录,是否有可能出现死锁?

1 个答案:

答案 0 :(得分:0)

根本没有机会 。在Postgres中,单个查询不仅永远不会死锁(请参阅注释),在并发事务中也不存在与同一查询结合的死锁的可能性。

死锁的最低“要求”:

  • 至少两个竞争并发交易。
  • 两者都必须锁定其他人之后尝试访问的资源。
  • 两者都必须稍后尝试访问由另一个事务锁定的资源。所以至少有两个人等待对方完成。

理论上两个并发,如果有多个行具有相同的DEPT_IT,则显示的相同调用可能会出现死锁。由于ORDER BY没有DELETE,因此可以对行进行排他行锁定以任意顺序删除。两个相同的命令可能以不同的行开头,最终会相互死锁。

实际上,这不会发生,因为并发删除将以相同的顺序进行锁定,从而排除任何可能的死锁。我们在同一个事务中需要额外的并发事务或更多命令,试图无序地锁定资源。

但所有这些都是 完全无关,因为要更新的列也在WHERE子句中。 (即使涉及列上的索引。)由于Postgres的MVCC模型,它无论如何都会编写新的行版本,无论哪些列实际更新。

如果您应该遇到涉及无序行锁的死锁,您可以使用SELECT .. FOR UPDATE使用确定性 ORDER BY解决此问题在子查询中: