【问题标题】:Postgres - Deadlock while updating a column that is also part of where clausePostgres - 在更新也是 where 子句的一部分的列时出现死锁
【发布时间】:2016-09-29 11:45:55
【问题描述】:

我的同事和我想知道,在更新过程中,如果在where 子句中使用同一列,是否正在更新列,这可能会导致死锁。

例如:

UPDATE EMPLOYEES
SET DEPT_ID = NULL
WHERE DEPT_ID = 13;

那么如果表EMPLOYEES 包含大约一百万条记录,是否存在死锁的可能性?

【问题讨论】:

  • 绝对不是。这是一个完全合法的更新查询。
  • 如果只有 一个 查询正在运行,我认为不会出现死锁。每当您更新多行时,其他查询可能会尝试更新或删除这些行,从而导致潜在的死锁情况,但使用 where 中的更新列不是原因。
  • 死锁总是涉及至少 两个事务。单个语句永远不会“自己死锁”。
  • 那么你有答案了吗?

标签: sql postgresql


【解决方案1】:

根本不可能出现死锁。不仅单个查询在 Postgres 中不会自己死锁(参见 cmets),而且在并发事务中与相同查询结合使用时也不会出现死锁。

死锁的最低“要求”:

  • 至少有两个相互竞争的并发事务。
  • 两者中的每一个都必须锁定其他一个将在以后尝试访问的资源。
  • 两者都必须稍后尝试访问被另一个事务锁定的资源。这样至少有两个等待另一个完成。

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

实际上,这不会发生,因为两个并发删除都会以相同的顺序获取锁,从而避免任何潜在的死锁。我们需要额外的并发事务或同一事务中的更多命令来尝试将资源锁定为无序。

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

如果您应该遇到涉及乱序行锁的死锁,您可以在子查询中使用带有 确定性 ORDER BYSELECT .. FOR UPDATE 解决它:

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-07
    • 1970-01-01
    相关资源
    最近更新 更多