![](/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.