我有一个在PostgreSQL中使用队列表的并行进程。逻辑是:
最多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
有重复的事实。选择锁定某些行,但然后查询更新而不是锁定的那些行。这就是为什么并发运行查询可能会尝试更新与此相同的行。所以SKIP LOCKED
在这种情况下不起作用。
鉴于行的更新可能以不同的顺序发生,第一个查询(尝试更新,比如第1行和第2行)可能首先更新第1行,然后尝试更新第2行,但等待锁定。并发运行查询(尝试更新1和2)已经更新了第2行并等待第1行的锁定。因此死锁。
您需要使用唯一标识符在锁定后更新行。