Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/database/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/jpa/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
PostgreSQL在尝试获取更新记录时发生死锁_Sql_Database_Postgresql - Fatal编程技术网

PostgreSQL在尝试获取更新记录时发生死锁

PostgreSQL在尝试获取更新记录时发生死锁,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

我有一个多进程在一个表中对帐户执行一些工作。我实现了一个查询,每个进程通过在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 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个,为什么不在一个事务中进行所有处理?您可以尝试各种缓解措施,但哪种缓解措施取决于它的设计方式。是的,这几乎是实现这一点并保持并发性的唯一方法,而无需跳过锁定或控制任务分发过程。