PostgreSQL在尝试获取更新记录时发生死锁
我有一个多进程在一个表中对帐户执行一些工作。我实现了一个查询,每个进程通过在lock列中设置一个值来锁定100条随机解锁的记录,并返回锁定的IDPostgreSQL在尝试获取更新记录时发生死锁,sql,database,postgresql,Sql,Database,Postgresql,我有一个多进程在一个表中对帐户执行一些工作。我实现了一个查询,每个进程通过在lock列中设置一个值来锁定100条随机解锁的记录,并返回锁定的ID UPDATE accounts SET locked = now() WHERE account_id in (SELECT account_id FROM accounts WHERE last_account_info_fetched IS NULL AND locked IS NULL LIMIT 10
UPDATE accounts SET locked = now() WHERE account_id in
(SELECT account_id FROM accounts
WHERE last_account_info_fetched IS NULL AND locked IS NULL
LIMIT 100
FOR UPDATE)
RETURNING account_id
在另一个事务中,从第一个查询返回一组ID的过程会进行更新并解锁记录
UPDATE accounts SET last_account_info_fetched = ?, locked = NULL WHERE account_id = ?
问题是,当多个进程运行第一个查询时,会导致死锁。如何解决这个问题,使每个进程都能获得不同批次的ID,而不会出现死锁
ERROR: deadlock detected
Detail: Process 3428 waits for AccessExclusiveLock on tuple (16865,68) of relation 10409452 of database 10221183; blocked by process 8628.
Process 8628 waits for ShareLock on transaction 27789140; blocked by process 5340.
Process 5340 waits for ShareLock on transaction 27789126; blocked by process 3428.
如何为每个线程添加一个范围限制,使它们不会重叠:
UPDATE accounts SET locked = now() WHERE account_id in
(SELECT account_id FROM accounts
WHERE last_account_info_fetched IS NULL AND locked IS NULL
and account_id >= 0
and account_id <1000
LIMIT 100
FOR UPDATE)
RETURNING account_id
如果您能够找到一种方法使每个线程都有自己的范围,那么就不应该有这个问题。您可以让每个线程选择一个随机数,然后仅解锁该范围内的行,但在该场景中仍会偶尔出现重叠。您似乎在尝试实现一个工作队列/任务队列或消息传递系统 正如你所发现的,这比你预期的要难 我建议使用一个现有的完善的;查看ActiveMQ、ZeroMQ、芹菜、RQ、resqueue。。。许多其他消息和任务队列 不过,在PostgreSQL 9.5中,有一项工作应该会使这项工作变得更容易:跳过锁定补丁,它允许您选择前n条尚未被其他进程锁定的记录。下面是一个很好的答案: 以下是您的查询在修复后的外观:
UPDATE accounts SET locked = now() WHERE account_id in
(SELECT account_id FROM accounts
WHERE last_account_info_fetched IS NULL AND locked IS NULL
and account_id >= 0
and account_id <1000
ORDER BY account_id --that`s it
LIMIT 100
FOR UPDATE)
RETURNING account_id
你试过使用偏移量吗?没有,但是在这种情况下我该如何使用它,你有没有一个例子?这些进程在集群中运行,我不知道会有多少这样的工作进程,所以我不能预先分配工作。你为什么这样做?为什么一次100个,为什么不在一个事务中进行所有处理?您可以尝试各种缓解措施,但哪种缓解措施取决于它的设计方式。是的,这几乎是实现这一点并保持并发性的唯一方法,而无需跳过锁定或控制任务分发过程。