优化查询以更新 Oracle 中的数百万数据?

Posted

技术标签:

【中文标题】优化查询以更新 Oracle 中的数百万数据?【英文标题】:Optimizing query for updating millions of data in Oracle? 【发布时间】:2019-01-16 08:28:29 【问题描述】:

我有 3 张桌子:

表 A:1.7 亿条数据 表 B:1.7 亿条数据 表 C:1.3 亿条数据 表日志

如果 colA2 == colB2,我想用 colC4 的值更新列 colA1 >colB3 == colC3。我创建了一个表:

表 D:8000 万数据存储 colB2colC3 以加快查询速度。

我还在表 D 中添加了 colB3 的索引。

Table Log 用于存储每次迭代完成时的进度消息和完成时间(参见脚本)。

目前我的更新脚本是这样的:

v_str_log := 'Begin updating';
p_write_to_log(v_str_log);
commit;

for data_list in
(
    select distinct colC4
    from tableC
)
loop
    update tableA
    set colA1 = data_list.colC4
    where colA2 in
    (
        select colB2
        from tableD
        where colC3 = data_list.colC4
    )
    var_total := var_total + sql%rowcount;
    v_str_log := 'Updated ' || sql%rowcount || ' for ' || card.sim_type || ' with total ' || var_total || ' rows.';
    commit;
end loop;

我已经运行了这个程序,它在大约 6 小时内完成。但是我从日志中发现,对于第一个循环,300 万条数据执行了 3 分钟,但几次迭代之后,500 万条数据在大约 20 分钟内执行。查询的执行速度不如第一次迭代快

为什么会这样?脚本可以优化吗?

【问题讨论】:

看MERGE INTO指令 考虑到要更新数百万条记录,为什么不使用 BULK COLLECT 或 FORALL 呢?看看this 并考虑从内部循环中删除提交指令。这也为您节省了大量时间。如果在执行过程中发生崩溃 - 假设在 30 000 000 条记录之后,这 30 000 000 条异常记录仍将等待提交。 @q4za4 非常感谢您关于从循环中删除提交的建议。它将执行时间从大约 4 小时减少到 2 小时。 :) @q4za4 MERGE INTO 命令会显着改善上面的查询还是仅仅为了可读性? 【参考方案1】:

您必须查看 Oracle 的 Updatable Join View 功能 - 这正是您的用例。

首先连接子查询中的所有表(这将通过哈希连接有效地完成,而无需缓慢的逐行循环)。

UPDATE子查询

例子

create table a
(col1 number,
col2 number);

create table b
(col2 number,
col3 number);

create table c
(col3 number,
col4 number);

insert into a values(null,1);
insert into b values(1,2);
insert into c values(2,1);


update (
select a.col1, c.col4
from a 
join b on a.col2 = b.col2
join c on b.col3 = c.col3
)
set col1 = col4
;

请注意,UJV 有一些先决条件。当错过这会导致

ORA-01779: 无法修改映射到非键保留表的列

在您的情况下,您必须使用唯一索引支持表 BC 以保证 键保留视图

create unique index c_idx on c(col3);
create unique index b_idx on b(col2);

如果在您的生产表上无法做到这一点,只需使用您的临时表并在其上创建唯一索引,更新后的视图将更简单地仅连接两个表。

【讨论】:

以上是关于优化查询以更新 Oracle 中的数百万数据?的主要内容,如果未能解决你的问题,请参考以下文章

数据库中的数百万行,只需要这么多

从C#中的数据中删除特殊字符后如何将dbf文件中的数百万行数据上传到SQL Server

针对特定查找优化的索引

公司百万级数据查询优化方案

JPA 查询调用 getter 数百万次

如何在 SQL Server 中更新具有数百万行的大表?