PostgreSQL - FOR UPDATE SKIP LOCKED死锁

PostgreSQL - FOR UPDATE SKIP LOCKED deadlock

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

  1. 开始交易。
  2. 用一些随机生成的 ID 标记 100 条未处理的记录。
  3. 提交。
  4. 运行 一些繁重的应用程序逻辑需要一些时间,并且正在处理具有在步骤 2 中生成的 ID 的队列记录。
  5. 更新 100 条状态为 success/bad 的已处理记录。

最多 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

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

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

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