PostgreSQL-FOR UPDATE SKIP LOCKED死锁

时间:2018-08-31 14:28:13

标签: sql postgresql postgresql-9.5

我有一个并行过程,正在PostgreSQL中使用队列表。逻辑是:

  1. 开始交易。
  2. 用一些随机生成的ID标记100条未处理的记录。
  3. 提交。
  4. 运行一些繁琐的应用程序逻辑,这会花费一些时间,并在步骤2中处理具有生成ID的队列记录。
  5. 更新100条成功/不良状态的已处理记录。

多达20个线程正在执行这些步骤。 但是,有时当我尝试对查询执行两步操作时:

UPDATE QUEUE_TABLE 
SET QUEUE_TXN_GUID=$RANDOM_GUID,
QUEUE_STATUS=1 
WHERE QUEUE_ROW_GUID IN 
  (SELECT QUEUE_ROW_GUID from QUEUE_TABLE 
   WHERE QUEUE_STATUS IS NULL OR QUEUE_STATUS = -1 
   LIMIT 100 FOR UPDATE SKIP LOCKED) RETURNING QUEUE_ROW_GUID

我收到错误消息deadlock detected

我在第5步中使用的查询是 UPDATE QUEUE_TABLE SET CDC_QUEUE_REZ_STATUS=$STATUS WHERE CDC_QUEUE_REZ_TXN_GUID=$RANDOM_GUID;

我不知道为什么在第一次更新子查询中使用FOR UPDATE SKIP LOCKED时会遇到这种奇怪的死锁。

1 个答案:

答案 0 :(得分:1)

问题的原因是QUEUE_ROW_GUID中存在重复项。 Select锁定一些行,但是查询更新不锁定那些行。这就是为什么并发运行的查询可能尝试更新与此行相同的行。因此,SKIP LOCKED在这种情况下不起作用。

鉴于行的更新可能以不同的顺序发生,第一个查询(试图更新第1行和第2行)可能首先更新第1行,然后尝试更新第2行,但等待锁定。并发运行的查询(也尝试更新1和2)已经更新了第2行,并等待第1行的锁定。因此出现了死锁。

锁定行后,您需要使用唯一标识符来更新行。