2014-03-27 8 views
1

我試圖找到一種更好的方法,將數據從表中拖入另一個作爲更大處理項目的一部分。我認爲我可以通過BULK COLLECT和FORALL做到這一點,並拿起顯着的速度,但我不認爲我可以使用BULK COLLECT處理單個列引用...我有一個數據/應用程序遷移項目(MSSQL到Oracle 11.2)繼承。我試圖優化和檢查端到端......該過程的第一步是將舊數據(數據庫表,4.5M記錄,170列,全部以字符串格式)導入到另一個表中。Oracle數據轉換 - Bulk/ForALL將不起作用

初始轉換是基於遊標的,逐行循環,每列至少有一個函數用於清除/轉換。它很有效,但在測試系統上花費了很長時間 - 超過12個小時將450萬條記錄從一張表翻譯到另一張表,並且功能非常簡單。 在我有權訪問的本地實現中,他們在220k條記錄中限制了13000個單元ID號碼ID。

我在筆記本電腦上設置了一個更有限的開發系統,用於測試替代技術 - 並且可以獲得5倍以上的導入速度,但仍然是光標/逐行。我已將表格設置爲NOLOGGING並使用APPEND提示。我測試過/沒有索引。我不能用這個尺寸表做SELECT INTO - 它只是窒息而已。

有沒有另一種/更好的技術?我還能如何提高轉換速度?我是否做錯了W/BULK COLLECT(即有沒有辦法參考單個字段?)

如果有人有任何見解,請切入!我包括一個非常簡潔的程序版本,所以我可以顯示我的使用嘗試。同樣的事情(非常多)作爲普通的遊標循環來運行,而不是FORALL和(i)下標。我得到的錯誤是ORA-00913:太多的值。我已經完成了完整的插入語句,將字段與值進行匹配。我檢查了數據轉換函數 - 它們用於常規列作爲參數。我想知道如果他們不工作w/BULK COLLECT和/或FORALL,因爲下標?

更新的信息: 這是一個限制訪問的系統上,並且到現在爲止(等待帳戶),我一直有遠程診斷「真實」(客戶)DEV系統,通過對運行一個本地系統 - 分析代碼,數據,時間等。我的建議是由另一位開發人員提供的,他們會將結果反饋給我。認真。然而... @Mark,@Justin - 通常情況下,我會擺脫任何遊標不是?絕對?需要的地方,並儘可能使用SELECT INTO。這通常是我的第一個關於舊PL/SQL代碼的建議......(「Why,So.Cursor?」穿着Joker化妝)。這是我在本地系統上嘗試的第一件事,但它只是減慢了服務器的爬行速度,我放棄了測試。那是在實施減少的NOLOGGING之前 - 這是我嘗試觸摸開發系統時的嘗試。
在查看時序,查詢,連接,索引和哭泣之後,我推薦使用NOLOGGING並將其轉換爲INSERT/* + APPEND */- ,這是在其他進程中購買的時間,主要是建立在聯接之外的表。

re:「OID < ='000052000'」 - 當他們在cust dev系統中設置第一個轉換的代碼時,他們必須限制他們從PMS_OHF錶轉換的記錄數量。最初,他們可以在合理的時間內獲得13000個人員標識符進行處理。那13000個ID將會在大約22萬條記錄中,所以,當我上船時他們就是這麼做的。一些重寫,加入更正,和NOLOGGING /插入附加做了足夠大的差別,他們繼續。在本地系統上,我認爲13000太小 - 我認爲我沒有對遺留結果進行有意義的比較 - 所以我將其升高並加以提升。我應該勇敢地嘗試在筆記本電腦開發系統上進行全面轉換 - 在這裏我至少可以通過EM觀察發生了什麼......政府不會允許他們的DBA使用它。

BIGGER信息(!?): - 再次回味00913錯誤,並回想起其他項目後,我意識到,當一個以上的元素被傳遞到預期的單個元素的函數先前的錯誤是...它指向我tp我試圖在BULK COLLECT循環中使用下標字段名稱。我重新觀看了幾個Steven Feuerstein YT演示文稿,我認爲它終於沉入其中。簡單的Web示例...我正在水平製作我的類型,而不是垂直(反之亦然)...爲了讓我的函數調用工作,我認爲我必須爲每個字段和該類型的ARRAY/TABLE做一個TYPE。突然間(170次)我在考慮一些關於手動並行的Tom Kyte課程,並要求wx我可以訪問新的(11.2?)DBMS_PARALLEL_EXECUTE接口 - 我懷疑它。此外,不知道更多關於客戶開發系統,除了最好的描述「不足」之外,我不知道wx // ism會是一個巨大的幫助。我需要閱讀// ism

我所知道的是,我必須完成一些完整的運行,否則我不會感到舒服,認爲我們的結果與傳統結果「足夠接近」。對於我們的測試,我們可能沒有太多的選擇。

 PROCEDURE CONVERT_FA IS  

    CURSOR L_OHF IS -- Cursor used to get SOURCE TABLE data 
     SELECT * 
     FROM TEST.PMS_OHF -- OHF is legacy data source 
     where OID <= '000052000' -- limits OHF data to a smaller subset 
     ORDER BY ID ; 

    L_OHF_DATA TEST.PMS_OHF%ROWTYPE; 
    L_SHDATA TEST.OPTM_SHIST%ROWTYPE; 

    Type hist_Array is table of TEST.PMS_OHF%ROWTYPE; 
    SHF_INPUT hist_array ; 



    Type Ohist_Array is table of TEST.OPTM_SHIST%ROWTYPE; 
    TARG_SHIST ohist_Array ; 

    n_limit number := 1000 ;  

    BEGIN 

    begin 

     OPEN L_OHF; 

     LOOP 
     FETCH L_OHF BULK COLLECT INTO SHF_INPUT LIMIT n_limit ; 
     FORALL i in 1 .. n_limit 
      INSERT INTO TEST.OPTM_SHIST 
     ( -- There are 170 columns in target table, requiring diff't xformations 
       RECORD_NUMBER , UNIQUE_ID , STRENGTH_YEAR_MONTH , FY , FM , ETHNIC , 
       SOURCE_CODE_CURR , SOURCE_CODE_CURR_STAT , 
       -- ... a LOT more fields 
       DESG_DT_01 , 
       -- and some place holders for later 
       SOURCE_CALC , PSID , GAIN_CURR_DT_CALC 
    ) 
     values 
     (-- examples of xformatiosn 
      SHF_INPUT.ID(i) , 
      '00000000000000000000000' || SHF_INPUT.IOD(i) , 
      TEST.PMS_UTIL.STR_TO_YM_DATE(SHF_INPUT.STRYRMO(i)) , 
      TEST.PMS_UTIL.STR_TO_YEAR(SHF_INPUT.STRYRMO(i)) , 
      TEST.PMS_UTIL.STR_TO_MONTH(SHF_INPUT.STRYRMO(i)) , 
      TEST.PMS_UTIL.REMOVE_NONASCII(SHF_INPUT.ETHNIC(i)) , 
      -- ... there are a lot of columns 
      TEST.PMS_UTIL.REMOVE_NONASCII(SUBSTR(SHF_INPUT.SCCURPRICL(i),1,2)) , 
      TEST.PMS_UTIL.REMOVE_NONASCII(SUBSTR(SHF_INPUT.SCCURPRICL(i),3,1)) , 

      -- an example of other transformations 
      (case 
       when ( 
         ( 
         SHF_INPUT.STRYRMO(i) >= '09801' 
         AND 
         SHF_INPUT.STRYRMO(i) < '10900' 
        ) 
        OR 
        ( 
         SHF_INPUT.STRYRMO(i) = '10901' 
         AND 
         SHF_INPUT.DESCHGCT01(i) = '081' 
        ) 
        ) 

       then TEST.PMS_UTIL.STR_TO_DATE(SHF_INPUT.DESCHGCT01(i) || SHF_INPUT.DESCHGST01(i)) 

       else TEST.PMS_UTIL.STR_TO_DATE(SHF_INPUT.DESCHGDT01(i)) 
      end), 

      -- below are fields that will be filled later 
      null , -- SOURCE_CALC , 
      SHF_INPUT.OID(i) , 
      null -- GAIN_CURR_DT_CALC 
      ) ; 

     EXIT WHEN L_OHF%NOTFOUND; -- exit when last row is fetched 

     END LOOP; 

     COMMIT; 

     close L_OHF; 

    END; 
    end CONVERT_OHF_FA; 
+0

當您執行「SELECT INTO」時會產生什麼「扼流圈」?你是說這需要很長時間嗎?如果是這樣,查詢計劃是什麼? 「PMS_OHF」表中有多少行?有多少人擁有「OID」=「000052000」? 'oid'索引? –

+1

另外,您是否已經追蹤了足夠的代碼,以便能夠確定在各種功能中花費了多少時間,與從源代碼讀取或寫入目標所花費的時間有多少?你的等待事件是什麼樣子的?你能利用並行性嗎? –

+2

從看看縮小的示例,PL/SQL有特定需求嗎?任何原因你不能「插入/ * +追加* /進入new_table從old_table中選擇col1,col2,some_transform_function(col3),some_other_transform_function(col4);」這將是迄今爲止性能最好的解決方案。如果所有的轉換都可以在可以立即應用的功能上完成,那將是一條可行的路。 –

回答

0

下降這對於其他問題之後,我今天再次就撿起。

有人給我發了他們類似代碼的一小段代碼,我決定坐下來,只是蠻橫的問題:轉到列的最小值並匹配值,並增加列/值並重新編譯。 ..

然後它打我...我的指數是在錯誤的地方。

不正確形式:

SHF_INPUT.ID(i) , 
    '00000000000000000000000' || SHF_INPUT.IOD(i) , 
    TEST.PMS_UTIL.STR_TO_YM_DATE(SHF_INPUT.STRYRMO(i)) , 

正確的形式:

SHF_INPUT(i).ID , 
    '00000000000000000000000' || SHF_Input(i).IOD , 
    TEST.PMS_UTIL.STR_TO_YM_DATE(SHF_Input(i).STRYRMO) , 

我責怪看着早期多列批量收集例子,假設我可以將它們轉換爲%ROWTYPE例子關閉我的頭頂。我感到不耐煩,沒有檢查。

感謝您的幫助和建議。

0
execute immediate 'alter session enable parallel dml'; 
INSERT /*+ APPEND PARALLEL */ INTO TEST.OPTM_SHIST(...) 
SELECT ... 
FROM TEST.PMS_OHF 
WHER OID <= '000052000'; 

這是做大量的數據負載的途徑。不要被像批量收集,管道表等所有花哨的PL/SQL選項所迷惑,它們很少比普通的舊SQL更快或更易於使用。這些特性的主要好處是在不進行重大重構的情況下提高逐行處理過程的性能。

在這種情況下,它看起來像PL/SQL中幾乎沒有邏輯。幾乎所有的PL/SQL都可以被拋出並被一個查詢替換。這使得它更易於修改,調試,添加並行等

一些其他提示:

  1. ORDER BY可能是不適合數據加載很有幫助。除非你試圖用索引來做一些事情,比如改進集羣因子或者重建而不進行排序。
  2. 確保你的函數聲明爲DETERMINISTIC如果輸出始終是相同的輸入相同。這可以幫助Oracle避免爲相同的結果調用函數。爲了更好的性能,可以聯所有的SQL語句的功能,但是這會導致混亂。
  3. 如果您仍然需要使用BULK COLLECT,使用提示APPEND_VALUES,不APPEND
+0

冰山一角 - 來自舊的大型機平日文件,由非db程序員提供。而不是直接的SQL。第一步是讓他們的代碼運行,證明我們可以匹配傳統結果。第二是說服他們需要完全重新設計。批量是多個表重新構建,全部使用(不必要的)ORDER BY。 XFORM fcns很簡單,後來fcns *需要* DETERMINISTIC - 糟糕的設計。 BULK COLLECT是否需要:168個源列中的每一個的column%類型的TABLE類型的變量?那是我最後的結論......我錯了嗎? – Marc

+0

您應該可以使用%ROWTYPE而不是許多%TYPE。 –

+0

這就是我所嘗試的,然後調出ROWTYPE中的列,但我一直得到** ORA-00913:太多的值**。我認爲我處理的是錯誤的列 - 上次我得到的是在一個fcn上被SELECT調用,在調用中傳遞了超過1行。如果我可以使用%ROWTYPE,我會非常高興...... – Marc