嗨我有两个表,每行有一百万行。我有oracle 11 g R1 我相信我们中的许多人都必须经历这种情况。
从一个表更新到另一个表的值是不同的最快捷方式是什么。
例如:表1有4个NUMBER列,具有高精度,例如:0.2212454215454212
表2有6列。 更新表2的四列基于两个表上的公共列,只有不同的列。
我有类似的东西
DECLARE
TYPE test1_t IS TABLE OF test.score%TYPE INDEX BY PLS_..;
TYPE test2_t IS TABLE OF test.id%TYPE INDEX BY PLS..;
TYPE test3_t IS TABLE OF test.Crank%TYPE INDEX BY PLS..;
vscore test1_t;
vid test2_t;
vurank test4_t;
BEGIN
SELECT id,score,urank
BULK COLLECT INTO vid,vscore,vurank
FROM test;
FORALL i IN 1 .. vid.COUNT
MERGE INTO final T
USING (SELECT vid (i) AS o_id,
vurank (i) AS o_urank,
vscore (i) AS o_score FROM DUAL) S
ON (S.o_id = T.id)
WHEN MATCHED THEN
UPDATE SET T.crank = S.o_crank
WHERE T.crank <> S.o_crank;
由于数字具有高精度,它是否会减慢?
如果我必须更新100万行,我尝试批量收集和合并组合仍然花费时间约30分钟用于最坏情况。
有什么与rowid? 将不胜感激。
答案 0 :(得分:2)
如果要更新所有行,请使用update:
update table_1
set (col1,
col2) = (
select col1,
col2
from table2
where table2.col_a = table1.col_a and
table2.col_b = table1.col_b)
批量收集或任何PL / SQL技术总是比纯SQL技术慢。
数值精度可能不重要,而且rowid不相关,因为两个表之间没有共同的值。
答案 1 :(得分:2)
当处理数百万行时,并行DML是游戏规则改变者。当然,你需要让Enterprise Edition使用并行,但它确实是唯一会产生很大差异的东西。
我建议您通过rleishman比较8 Bulk Update Methods阅读一篇关于OraFAQ的文章。他的主要发现是“到目前为止,磁盘读取的成本超过了它们几乎不可察觉的上下文切换(原文如此)”。换句话说,除非您的数据已经缓存在内存中,否则SQL和PL / SQL方法之间确实没有显着差异。
这篇文章确实有一些关于使用并行的简洁建议。令人惊讶的结果是并行流水线功能提供了最佳性能。
答案 2 :(得分:1)
关注语法并跳过逻辑(可能使用纯更新+纯插入可以解决问题,合并成本,索引,合并时可能的全扫描等)
您应该在批量收集语法中使用 Limit
使用无限制的批量收集
两者都会导致性能低下。
DECLARE
v_fetchSize NUMBER := 1000; -- based on hardware, design and .... could be scaled
CURSOR a_cur IS
SELECT id,score,urank FROM test;
TYPE myarray IS TABLE OF a_cur%ROWTYPE;
cur_array myarray;
BEGIN
OPEN a_cur;
LOOP
FETCH a_cur BULK COLLECT INTO cur_array LIMIT v_fetchSize;
FORALL i IN 1 .. cur_array.COUNT
// DO Operation
COMMIT;
EXIT WHEN a_cur%NOTFOUND;
END LOOP;
CLOSE a_cur;
END;
答案 3 :(得分:0)
只是为了确保:test.id
和final.id
必须编入索引。
首先select ... from test
您从Table 1
获得了太多记录,之后您需要将所有记录与Table 2
上的记录进行比较。尝试仅选择您需要更新的内容。因此,至少有两种变体:
a)仅选择更改的记录:
SELECT source_table.id, source_table.score, source_table.urank
BULK COLLECT INTO vid,vscore,vurank
FROM
test source_table,
final destination_table
where
source_table.id = destination_table.id
and
source_table.crank <> destination_table.crank
;
b)使用datetime值向源表添加新字段,并将其填入当前时间的触发器中。同步选择仅在最后一天更改的记录。该字段需要编入索引。
在更新阶段进行此类更改后,您无需比较其他字段,只匹配ID:
FORALL i IN 1 .. vid.COUNT
MERGE INTO FINAL T
USING (
SELECT vid (i) AS o_id,
vurank (i) AS o_urank,
vscore (i) AS o_score FROM DUAL
) S
ON (S.o_id = T.id)
WHEN MATCHED
THEN UPDATE SET T.crank = S.o_crank
如果您担心撤消/重做段的大小,那么变体b)
会更有用,因为您可以将源Table 1
中的记录划分为时间片,并在更新每个片后提交更改。例如。从00:00到01:00,从01:00到02:00等
在此变体中,只需通过SQL语句即可完成更新,而无需在行中保存可接受大小的重做/撤消日志的数据。