选择更新甚至排序之间的 PostgreSQL 死锁

标签 postgresql concurrency postgresql-9.2 database-deadlocks

我有两个死锁在一起的查询

PERFORM id
FROM stack
WHERE id IN (SELECT tmp.stkid FROM tmp_push_bulk tmp WHERE tmp.stkid > 0)
ORDER BY id
FOR UPDATE OF stack

PERFORM stk.id
FROM stack stk
WHERE stk.referer IN (
      SELECT tmp.id
      FROM tmp_renew_stk tmp
)
ORDER BY stk.id
FOR UPDATE OF stk

错误是:

- PG (20:46:37) [14786]: Execute command failed: ERROR:  deadlock detected
DETAIL:  Process 14797 waits for ShareLock on transaction 183495696; blocked by process 24303.
Process 24303 waits for ShareLock on transaction 183495704; blocked by process 14797.
HINT:  See server log for query details.

我还认为每个进程都按照 id 列的顺序锁定它的行,所以死锁是不可能的。谁能告诉我为什么?

最佳答案

可能是 IN 表达式以非特定顺序锁定行(未经测试)。在可能的情况下,我通常会用 JOIN 替换更大集合上的 IN 。这开始速度更快,从而最大限度地减少了死锁的机会。我会尝试:

更新:根据您的评论,您有很多重复项。假设临时表中存在重复项,我建议将子查询用于三个目的:

  • 折叠重复项。
  • 使用 DISTINCT 同时对子查询中的行进行排序特别便宜。
  • 应用 WHERE 条件 AND tmp.stkid > 0

PERFORM s.id
FROM  stack s
JOIN  (
   SELECT DISTINCT stkid
   FROM   tmp_push_bulk
   WHERE  stkid > 0
   ) tmp ON tmp.stkid = s.id 
ORDER BY 1
FOR   UPDATE OF s;

和:

PERFORM s.id
FROM  stack s
JOIN  (
   SELECT DISTINCT id
   FROM   tmp_renew_stk
   ) tmp ON tmp.id = s.referer
ORDER BY 1
FOR   UPDATE OF s;

关于选择更新甚至排序之间的 PostgreSQL 死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/20786148/

相关文章:

java - 从 ExecutorService 访问队列 (LinkedBlockingQueue) 的正确方法

postgresql - Postgresql下使用to_tsquery搜索奇怪的结果

PostgreSQL : SSL with TCP connections

将不同项目分组到桶中的sql查询

postgresql - Vault - AWS RDS Postgres 集成

java - 调用 self 时不遵守 EJB Singleton WRITE 锁

java - ConcurrentHashmap 同时进行写入和获取操作

sql - 来自 phpPgAdmin 的 Postgresql 插入查询语法错误

sql - 在postgres中的单个表上查询多行和多列

sql - 对一组列的 NOT NULL 约束