优化查询以更新 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 万数据存储 colB2 和 colC3 以加快查询速度。我还在表 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: 无法修改映射到非键保留表的列
在您的情况下,您必须使用唯一索引支持表 B
和 C
以保证 键保留视图
create unique index c_idx on c(col3);
create unique index b_idx on b(col2);
如果在您的生产表上无法做到这一点,只需使用您的临时表并在其上创建唯一索引,更新后的视图将更简单地仅连接两个表。
【讨论】:
以上是关于优化查询以更新 Oracle 中的数百万数据?的主要内容,如果未能解决你的问题,请参考以下文章