在 Postgres 中提取全表的最快方法

Ima*_* Y. 5 postgresql dump copy postgresql-11

我正在尝试将一个包含 50M 记录的表转储到一个文件中,我的目标是减少执行此操作的时间。我通常使用COPY metrics TO 'metrics.csv' DELIMITER ',' CSV;在最好的情况下这可能需要一个小时。我也有兴趣以某种普通格式导出数据(避免使用pd_dump目录)。

其中一个想法是通过条件或游标以某种方式访问​​此表,该条件或游标将整个表拆分为相同大小的部分,因此您可以同时执行例如 2 个复制查询,从而将时间减少一半。

例子:

COPY (SELECT * FROM metrics WHERE id < 25000000) TO 'metrics_1.csv' DELIMITER ',' CSV;
COPY (SELECT * FROM metrics WHERE id >= 25000000) TO 'metrics_2.csv' DELIMITER ',' CSV;
Run Code Online (Sandbox Code Playgroud)

在这些条件下创建的部分索引有帮助吗?

有什么想法是实现表的这种部分复制转储的好方法吗?有没有其他解决方案可以更快地转储此表?

Postgresql 11 / 100GB RAM / 20 核。

在与COPYIO 边界进行一些并行化之后,这似乎不是瓶颈。

在此处输入图片说明

jja*_*nes 4

您当前对主键使用范围查询的想法可能是最好的选择。我不明白部分索引对此有什么帮助。您将需要一系列部分索引,这些索引聚合起来就是一个总索引,并且使用用于范围查询的 BTREE 索引是毫无意义的。但是,此方法的成功可能取决于表中的行在物理上大致按主键值排序。您可以使用 CLUSTER 命令强制执行此排序,但这本身就是一个非常昂贵的操作。

如果你想让 PostgreSQL 为你并行化,你可以使用一个虚拟查询来选择所有内容:

COPY (SELECT * FROM metrics) TO 'metrics.csv' DELIMITER ',' CSV;
Run Code Online (Sandbox Code Playgroud)

并且您可能还需要大幅降低“parallel_tuple_cost 设置”,也许一直降低到零。但这不太可能给您带来实际的改进,因为瓶颈(如果不是磁盘 IO)将在于将数据从其内部二进制格式转换为将由 COPY 输出的文本格式。这种转换总是在领导进程中完成,而不是在并行工作进程中完成。

您可以通过编写查询来解决这个问题,以便在查询本身中显式完成繁重的工作:

COPY (SELECT col1::text, col2::text, col3::text, ... FROM metrics) TO 'metrics.csv' DELIMITER ',' CSV;
Run Code Online (Sandbox Code Playgroud)

现在,引导进程仍然需要扫描所有文本以查找需要转义/引用的内容,但至少它不需要自行将所有行的 JSONB 转换为文本。在我看来,使用 7 个并行工作进程(包括领导者在内的 8 个进程)可以将所需的时间减少COPY...TO一半。然后,开销就变成了从并行工作进程到主导进程的通信。删除它的方法是在单独的会话中返回索引范围查询的原始建议。