PostgreSQL - FOR UPDATE SKIP LOCKED死锁

问题描述 投票:1回答:1

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

  1. 开始交易。
  2. 使用一些随机生成的ID标记100个未处理的记录。
  3. 承诺。
  4. 运行一些需要一些时间的重型应用程序逻辑,并在步骤2中处理带有生成ID的队列记录。
  5. 更新100处理成功/状态不佳的记录。

最多20个线程正在执行这些步骤。但是,有时当我尝试使用查询执行2步时:

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这个奇怪的死锁。

sql postgresql postgresql-9.5
1个回答
1
投票

问题的原因是QUEUE_ROW_GUID有重复的事实。选择锁定某些行,但然后查询更新而不是锁定的那些行。这就是为什么并发运行查询可能会尝试更新与此相同的行。所以SKIP LOCKED在这种情况下不起作用。

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

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

© www.soinside.com 2019 - 2024. All rights reserved.