PostgreSQL 9.6 嵌套 INSERT/RETURN 语句的 CTE 性能差得令人无法接受

问题描述 投票:0回答:1

我有一个大表(> 50M 行),我正在尝试将其转换为新的表格式。作为此过程的一部分,从第一次插入返回的行 ID 需要在第二次插入到第二个表中时使用。

我使用的 CTE 看起来像这样:

WITH inserted_data AS (
    INSERT INTO table1 (column1, column2, column3, column4)
    SELECT value1, value2, value3, value4
    FROM original_table
    RETURNING rowid, column4
)
INSERT INTO table2 (table1_id, column4)
SELECT rowid, column4
FROM inserted_data;

问题是,这慢得令人无法接受。仅 4800 行需要 21 秒,而 9600 行则需要大约 50 秒。按照这个速度,我预计 5000 万条记录大约需要 3 天的时间。我的时间限制在2小时左右。

如果我只执行第一次插入(无 CTE),查询速度会快 100 倍,对于 4800 行和 9600 行分别大约需要 200 毫秒和 500 毫秒。我知道第二次插入的时间也可以忽略不计。按照这个速度,查询将在指定的时间内完成。

问题是,我如何重写查询以按照单个查询可以完成的速度执行。将数据库中的所有数据转移到外部程序中会很麻烦且容易出错,并且需要额外的资源。如果我做一些类似编写带有循环的函数之类的事情,那么我不会一次性插入,并且我预计那里的性能也会很差。我认为使用临时表没有帮助,因为问题似乎仅在于 CTE 的存在。

我试过这个:

INSERT INTO table2 (table1_id, column4)
SELECT rowid, column4
FROM (
    WITH inserted_data AS (
        INSERT INTO table1 (column1, column2, column3, column4)
        SELECT value1, value2, value3, value4
        FROM original_table
        RETURNING rowid, column4
    )
)

但这给了我:

syntax error at or near "INTO"
sql database postgresql-9.6
1个回答
0
投票

如何将插入分成两个语句?第二个

insert
可能看起来像:

INSERT INTO table2
       (table1_id, column4)
SELECT t1.rowid
,      ot.column4
FROM   original_table ot
JOIN   table1 t1 
ON     t1.column1 = ot.value1
       AND t1.column2 = ot.value2
       AND t1.column3 = ot.value3
       AND t1.column4 = ot.value4

对于

original_table
中的每一行,连接条件会查找插入到
table1
中的行。

© www.soinside.com 2019 - 2024. All rights reserved.