簡體   English   中英

使用Rowid從一張表更新百萬行到另一張Oracle

[英]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
無限制使用批量收集

  1. 將所有記錄都裝入內存
  2. 沒有部分提交的合並,您將創建一個大的重做日志,該重做日志必須在流程結束時應用。

兩者都會導致性能降低。

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;
  1. 只是要確保:必須對test.idfinal.id進行索引。

  2. 第一次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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM