![](/img/trans.png)
[英]Is it possible to copy some rows from one table to the other along with rowids?
[英]Update million rows using rowids from one table to another Oracle
嗨,我有两个表,每个表都有一百万行。我有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吗? 帮助将不胜感激。
如果要更新所有行,则只需使用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不相关,因为两个表之间没有通用值。
当处理数百万行时,并行DML会改变游戏规则。 当然,您需要具有企业版才能使用并行,但这实际上是唯一会带来很大变化的东西。
我建议您阅读rleishman比较8 Bulk Update Methods的有关OraFAQ的文章。 他的主要发现是“到目前为止,磁盘读取的成本远远超过了上下文切换,因此几乎看不到(原文如此)”。 换句话说,除非您的数据已经缓存在内存中,否则SQL和PL / SQL方法之间确实没有显着差异。
本文确实对并行应用提出了一些巧妙的建议。 令人惊讶的结果是并行流水线功能可提供最佳性能。
专注于已使用的语法并跳过逻辑 (可能使用纯更新+纯插入可能会解决问题,合并成本,索引,可能对合并进行全面扫描等)
您应该在Bulk Collect语法中使用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;
只是要确保:必须对test.id
和final.id
进行索引。
第一次select ... from test
您从Table 1
获得了太多记录,然后需要将所有这些与Table 2
记录进行比较。 尝试仅选择您需要更新的内容。 因此,至少有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)使用日期时间值将新字段添加到源表中,并在触发器中填充当前时间。 在同步选择时,仅记录在过去一天中发生了更改。 该字段需要索引。
在更新阶段进行了此类更改之后,您无需比较其他字段,只需匹配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语句即可完成更新,而不必在保持可接受的重做/撤消日志大小的情况下,将数据选择到行的集合中。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.