更新 Postgresql 数据库中约 1 亿行的最有效方法?

cha*_*der 1 sql database postgresql crud bigdata

我有一个只有一张表的数据库。该表需要每隔几周更新一次。我们需要将第三方数据引入其中,它将包含 100-1.2 亿行。所以流程基本上是:

  1. 从源头获取原始数据
  2. 检测插入、更新和删除
  3. 进行更新并摄取到数据库中

检测和执行更新的最佳方法是什么?一些选项是:

  1. 将传入数据与当前数据库一一比较并进行单次更新。这看起来很慢而且不可行。
  2. 将传入数据提取到新表中,然后用新表替换旧表
  3. 在当前表中就地批量更新。不知道该怎么做。

您认为最好的选择是什么,或者是否有其他选择?

THX*_*138 6

Postgres 有一个关于提高批量加载性能的有用指南。根据您的描述,除了批量和INSERT之外,您还需要执行批量操作 。以下是提高效率的大致分步指南:UPDATEDELETE

操作前配置全局数据库配置变量

ALTER SYSTEM SET max_wal_size = <size>;
Run Code Online (Sandbox Code Playgroud)

您还可以完全禁用 WAL。

ALTER SYSTEM SET wal_level = 'minimal';
ALTER SYSTEM SET archive_mode = 'off';
ALTER SYSTEM SET max_wal_senders = 0;
Run Code Online (Sandbox Code Playgroud)

请注意,这些更改需要重新启动数据库才能生效。

开始交易

您希望所有工作都在一个事务中完成,以防出现任何问题。跨多个连接并行运行 COPY 通常不会提高性能,因为磁盘通常是限制因素。

在事务级别优化其他配置变量

SET LOCAL maintenance_work_mem = <size>
...
Run Code Online (Sandbox Code Playgroud)

如果您要对 Postgres 内的数据进行任何其他特殊处理(work_mem通常是最重要的,特别是使用 Postgis 扩展时),您可能需要设置其他配置参数。请参阅本指南,了解对性能最重要的配置变量。

CREATETEMPORARY没有约束的表。

CREATE TEMPORARY TABLE changes(
  id bigint,
  data text,
) ON COMMIT DROP; --ensures this table will be dropped at end of transaction
Run Code Online (Sandbox Code Playgroud)

批量插入changes使用COPY FROM

使用COPY FROM命令将原始数据批量插入到临时表中。

COPY changes(id,data) FROM .. 
Run Code Online (Sandbox Code Playgroud)

DROP可能会减慢处理速度的关系

target表上的DROP所有外键约束、索引和触发器(如果可能)。不要删除您的主键,因为您需要将其用于INSERT.

target向表中添加跟踪列

向表中添加一列target以确定更改表中是否存在行:

ALTER TABLE target ADD COLUMN seen boolean;
Run Code Online (Sandbox Code Playgroud)

从表中UPSERT到表changestarget

UPSERT 是通过ON CONFLICT向标准INSERT语句添加子句来执行的。这避免了执行两个单独操作的需要。

INSERT INTO target(id,data,seen) 
  SELECT 
    id,
    data,
    true
  FROM
    changes
  ON CONFLICT (id) DO UPDATE SET data = EXCLUDED.data, seen = true;
Run Code Online (Sandbox Code Playgroud)

DELETE不在changes表中的行

DELETE FROM target WHERE not seen is true;
Run Code Online (Sandbox Code Playgroud)

DROP跟踪列和临时changes

DROP TABLE changes;
ALTER TABLE target DROP COLUMN seen;
Run Code Online (Sandbox Code Playgroud)

添加回您为了性能而放弃的关系

添加回已删除的所有约束、触发器和索引,以提高批量更新插入性能。

提交交易

批量更新插入/删除已完成,应在事务外部执行以下命令。

VACUUM ANALYZE在桌子上运行target

这将允许查询规划器对表做出适当的推断并回收死元组占用的空间。

SET maintenance_work_mem = <size>
VACUUM ANALYZE target;
SET maintenance_work_mem = <original size>
Run Code Online (Sandbox Code Playgroud)

恢复数据库配置变量的原始值

ALTER SYSTEM SET max_wal_size = <size>;
...
Run Code Online (Sandbox Code Playgroud)

您可能需要再次重新启动数据库才能使这些设置生效。