PostgreSQL - 1 亿条记录从存档传输到新 table

PostgreSQL - 100 million records transfer from archive to a new table

我需要传输 2 table 秒的数据(Table ATable B) 变成一个新的 table。 我正在使用一个查询来使用 ID 列连接 A 和 B tables。 Table A 和 B 是没有任何索引的 table 档案。 (百万条记录) Table X 和 Y 是具有良好索引的 A 和 B 的副本。 (几千条记录)

下面是我的项目的代码。

with data as 
(
  SELECT a.*, b.* FROM A_archive a
    join B_archive b where a.transaction_id = b.transaction_id
  UNION 
  SELECT x.*, y.* FROM X x 
    join Y y where x.transaction_id = y.transaction_id
 )
INSERT INTO 
Another_Table 
(
  columns
)
select * from data
On Conflict(transaction_id)
  do udpate ...

以上全部是在生产环境中运行,有将近1.4亿条记录。 由于此生产数据库需要将近 10 个小时来处理数据并失败。

我还在 AWS 中有一个 分布式作业调度程序 来在函数内安排此查询并每 5 小时检索一次最新记录。存档 tables 存储关闭的发票数据。 Pega UI 将使用此 table 检索有关已关闭发票的数据并向客户显示。

请提出一些性能更高的建议。

UNION 删除重复行。在大型未索引 table 上,这是一项昂贵的操作。如果不需要重复数据删除,请尝试 UNION ALL。它将节省重复数据删除所需的大量数据改组和比较。

如果您的档案 table 没有索引,您的 JOIN 操作将非常低效。至少索引您在 ON 子句中使用的 transaction_id 列。

你没有说你想用结果 table 做什么。在许多情况下,您可以根据自己的目的使用 VIEW 而不是 table。 VIEW 消除了创建派生 table 的工作。实际上,它使用派生结构将工作推迟到 SELECT 操作的时间。如果您的 SELECT 操作具有高度选择性的 WHERE 子句,则节省的费用将是惊人的。为了使其正常工作,您可能需要在您的档案 tables.

上放置适当的索引

当您可以枚举所需的列时,您可以使用 SELECT *。这肯定会在您的结果中添加一个冗余列:它会生成 transaction_id 的两个副本。它还可能生成其他冗余或未使用的数据。始终避免在生产软件中使用 SELECT *,除非您知道自己需要它。

请记住:SQL 是声明性的,而不是过程性的。您声明(描述)您需要的结果,然后让服务器找出获取结果的最佳方式。在 table 组合这样的情况下,VIEW 让服务器为您完成这项工作。它将尽可能使用您提供的索引。

那个 UNION 一定很昂贵,它几乎在后台构建一个 temp-table 包含所有 A-B + X-Y 记录,对其进行排序(在所有字段上)然后删除任何双打。如果您说涉及 1 亿条记录,那么正在进行大量排序,很可能会涉及换出到磁盘。

请记住,只有在预期存在重复项时才需要执行此操作

  • AB 之间 JOIN 的结果中
  • XY 之间的 JOIN 的结果中
  • 以上两者的综合结果

IF 这些都不是预期的,只需使用 UNION ALL 事实上,在那种情况下,为什么不对 A-B 进行 1 个 INSERT 操作,对 X-Y 进行另一个操作呢?按照描述,我会说 X-Y 中的任何内容都应该否决 A-B 中的任何内容,对吧?

此外,如 O.Jones 所述,无论是否归档表,它们至少应该在您正在 JOINtransaction_id 字段上带有一个(最好是聚集的)索引在。 (对于 Another_Table 顺便说一句)

综上所述,在 1 个事务中处理 1 亿条记录需要一些时间,只是要移动大量数据。但是 10h 确实听起来有点过分。