PostgreSQL - 1 亿条记录从存档传输到新 table
PostgreSQL - 100 million records transfer from archive to a new table
我需要传输 2 table 秒的数据(Table A 和 Table 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 亿条记录,那么正在进行大量排序,很可能会涉及换出到磁盘。
请记住,只有在预期存在重复项时才需要执行此操作
- 在
A
和 B
之间 JOIN
的结果中
- 在
X
和 Y
之间的 JOIN
的结果中
- 以上两者的综合结果
IF 这些都不是预期的,只需使用 UNION ALL
事实上,在那种情况下,为什么不对 A-B
进行 1 个 INSERT 操作,对 X-Y
进行另一个操作呢?按照描述,我会说 X-Y
中的任何内容都应该否决 A-B
中的任何内容,对吧?
此外,如 O.Jones 所述,无论是否归档表,它们至少应该在您正在 JOIN
的 transaction_id
字段上带有一个(最好是聚集的)索引在。 (对于 Another_Table
顺便说一句)
综上所述,在 1 个事务中处理 1 亿条记录需要一些时间,只是要移动大量数据。但是 10h 确实听起来有点过分。
我需要传输 2 table 秒的数据(Table A 和 Table 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 亿条记录,那么正在进行大量排序,很可能会涉及换出到磁盘。
请记住,只有在预期存在重复项时才需要执行此操作
- 在
A
和B
之间JOIN
的结果中 - 在
X
和Y
之间的JOIN
的结果中 - 以上两者的综合结果
IF 这些都不是预期的,只需使用 UNION ALL
事实上,在那种情况下,为什么不对 A-B
进行 1 个 INSERT 操作,对 X-Y
进行另一个操作呢?按照描述,我会说 X-Y
中的任何内容都应该否决 A-B
中的任何内容,对吧?
此外,如 O.Jones 所述,无论是否归档表,它们至少应该在您正在 JOIN
的 transaction_id
字段上带有一个(最好是聚集的)索引在。 (对于 Another_Table
顺便说一句)
综上所述,在 1 个事务中处理 1 亿条记录需要一些时间,只是要移动大量数据。但是 10h 确实听起来有点过分。