PostgreSQL之间的死锁选择更新甚至订购

时间:2013-12-26 14:00:33

标签: 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列的排序中锁定它的行,所以死锁是不可能的。谁能告诉我为什么?

1 个答案:

答案 0 :(得分:0)

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

更新:根据你的评论你有很多重复。假设临时表中的dupes我建议子查询有三个目的:

  • 折叠副本。
  • 使用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;