使用全局游标为多个客户端对postgresql中的数据进行分页



因此,我需要通过在不同服务器上运行的多个处理脚本实例同时处理一些巨大数据集(100000条以上的记录(的部分。每个实例都将处理自己的数据块,不会向多个实例提供任何数据。我会给每个实例提供50/100的记录块。问题是-如何组织分页我认为某些类型的全局指针应该存储在DB端(PostgreSQL(。CURSOR在这里不起作用,因为它存在于事务中。

数据集由多个文本文件组成,每行存储一行,并将通过b-index进行查询。示例列:uuidfile_namelineline_nrdate

我的想法是创建一个游标表,并在每次请求后为每个file_name存储游标当前值(将引用line_nr(。

这是一种有效的方法吗?还是PostgreSQL中有一些内置功能可以让我做到这一点?

选择跳过锁定进行更新。您需要创建一个包含claimed_at/completed_at时间戳列的工作队列表,工作人员在完成工作时会更新这些列。工作队列表的另一列将引用数据集表的PK(出于性能原因,您可能不想使用真正的外键(。然后您可以使用此查询的修改版本:

https://stackoverflow.com/a/49403339/16361

我们将使用一个更大的限制来同时分配任务块。而且,我们将设置claimed_at时间戳,而不是删除,并在claimed_at为null时使用过滤器,以避免重复声明。您的应用程序代码将负责第二次更新,以设置completed_at时间戳。作为第三个优势,您可以查询工作队列表的completed_at-claimed_at时间戳,以跟踪每个任务花费的时间,并且当所有操作都完成时,您可以在is NULL中查询completed_at,以查看导致工作人员崩溃或未完成的行。

UPDATE work_queue_table set claimed_at=now()
WHERE dataset_row_uuid = (
SELECT dataset_row_uuid
FROM work_queue_table
WHERE claimed_at IS NULL
FOR UPDATE SKIP LOCKED
LIMIT 50
)
RETURNING dataset_row_uuid;

工作队列表的设置可以如此简单:

CREATE TABLE work_queue_table AS
SELECT uuid AS dataset_row_uuid,
NULL::timestamp AS claimed_at,
NULL::timestamp AS completed_at
FROM the_dataset_table

尽管你需要把它变成一个常规的CREATE&如果花费太长时间,可以并行运行多个INSERT(由于PG获得了多处理功能,我还没有创建过这样的大表,这可能实际上不再有帮助(。

如果由同一个工作人员处理同一文件中的任务很好/很有帮助,则可以将ORDER by改为file_name、line_nr。对于各种用例,你可以做很多调整,希望这能让你开始。

如果客户端数量不变,每个客户端都可以使用获取下一批

SELECT ...
FROM atable
WHERE id > previous_id
AND id % number_of_clients = client_no
ORDER BY id
LIMIT 50;

这里,previous_id是来自前一批的最大idnumber_of_clients是客户端的数量,并且client_no对于每个客户端是不同的。

这样可以避免在不需要锁的情况下取锁。

最新更新