2014-01-13 27 views
3

我想從一個表中獲取大約6百萬行並將其插入到另一個表中。 我如何使用批量收集和提交?如何使用批量收集並插入到Pl/SQl

+2

我建議不要在所有使用遊標。性能上簡單的'insert ... into ... select ... from'會更高效。而且你還應該發佈一些代碼,展示你的嘗試以及你面臨的具體問題。 –

+2

簡單 - 'CREATE TABLE new_tbl_with_6m_rec AS SELECT * FROM old_tbl_with_6m_rec WHERE whatever_conditions;' – Rachcha

回答

1

oracle

Below is an example From

CREATE OR REPLACE PROCEDURE fast_way IS 

TYPE PartNum IS TABLE OF parent.part_num%TYPE 
INDEX BY BINARY_INTEGER; 
pnum_t PartNum; 

TYPE PartName IS TABLE OF parent.part_name%TYPE 
INDEX BY BINARY_INTEGER; 
pnam_t PartName; 

BEGIN 
    SELECT part_num, part_name 
    BULK COLLECT INTO pnum_t, pnam_t 
    FROM parent; 

    FOR i IN pnum_t.FIRST .. pnum_t.LAST 
    LOOP 
    pnum_t(i) := pnum_t(i) * 10; 
    END LOOP; 

    FORALL i IN pnum_t.FIRST .. pnum_t.LAST 
    INSERT INTO child 
    (part_num, part_name) 
    VALUES 
    (pnum_t(i), pnam_t(i)); 
    COMMIT; 
END 
+0

批量收集大記錄數量和沒有限制設置可以導致內存不足問題 – Sathya

7
declare 
    -- define array type of the new table 
    TYPE new_table_array_type IS TABLE OF NEW_TABLE%ROWTYPE INDEX BY BINARY_INTEGER; 

    -- define array object of new table 
    new_table_array_object new_table_array_type; 

    -- fetch size on bulk operation, scale the value to tweak 
    -- performance optimization over IO and memory usage 
    fetch_size NUMBER := 5000; 

    -- define select statment of old table 
    -- select desiered columns of OLD_TABLE to be filled in NEW_TABLE 
    CURSOR old_table_cursor IS 
    select * from OLD_TABLE; 

BEGIN 

    OPEN old_table_cursor; 
    loop 
    -- bulk fetch(read) operation 
    FETCH old_table_cursor BULK COLLECT 
     INTO new_table_array_object LIMIT fetch_size; 
    EXIT WHEN old_table_cursor%NOTFOUND; 

    -- do your business logic here (if any) 
    -- FOR i IN 1 .. new_table_array_object.COUNT LOOP 
    -- new_table_array_object(i).some_column := 'HELLO PLSQL';  
    -- END LOOP;  

    -- bulk Insert operation 
    FORALL i IN INDICES OF new_table_array_object SAVE EXCEPTIONS 
     INSERT INTO NEW_TABLE VALUES new_table_array_object(i); 
    COMMIT; 

    END LOOP; 
    CLOSE old_table_cursor; 
End; 

希望這有助於。

+1

不錯。 'COMMIT'的批量大小爲'fetch_size'。另外,你可以把'EXIT WHEN',立即移到'FETCH'嗎? –

+0

是的,EXIT WHEN可能在FETCH後立即(當前的語法只是我的習慣:),我在FORALL之後設置了COMMITE以防止創建一個大的redolog。感謝您的評論。 –

+0

請注意,您應該'退出時,new_table_array_object.COUNT = 0'而不是'退出時,old_table_cursor%NOTFOUND',所以你不會錯過任何行(見http://www.oracle.com/technetwork/issue-archive/2008 /08-mar/o28plsql-095155.html) – LPrc

0

SQL引擎解析並執行SQL語句,但在某些情況下會將數據返回到PL/SQL引擎。

在執行PL/SQL語句期間,每個SQL語句都會在兩個引擎之間導致上下文切換。當PL/SQL引擎找到SQL語句時,它停止並將控制權交給SQL引擎。 SQL引擎執行該語句並返回到PL/SQL引擎中的數據。這種控制轉移是調用上下文切換。通常PL/SQL引擎之間的切換非常快,但是上下文切換執行時間很大,從而影響性能。 SQL引擎檢索所有行並將它們加載到集合中並切換回PL/SQL引擎。使用批量收集多行可以通過單個上下文切換獲取。

舉例:1

DECLARE 

Type stcode_Tab IS TABLE OF demo_bulk_collect.storycode%TYPE; 
Type category_Tab IS TABLE OF demo_bulk_collect.category%TYPE; 
s_code stcode_Tab; 
cat_tab category_Tab; 
Start_Time NUMBER; 
End_Time NUMBER; 

CURSOR c1 IS 
select storycode,category from DEMO_BULK_COLLECT; 
BEGIN 
    Start_Time:= DBMS_UTILITY.GET_TIME; 
    FOR rec in c1 
    LOOP 
    NULL; 
    --insert into bulk_collect_a values(rec.storycode,rec.category); 
    END LOOP; 
    End_Time:= DBMS_UTILITY.GET_TIME; 
    DBMS_OUTPUT.PUT_LINE('Time for Standard Fetch :-' ||(End_Time-Start_Time) ||' Sec'); 

    Start_Time:= DBMS_UTILITY.GET_TIME;  
    Open c1; 
     FETCH c1 BULK COLLECT INTO s_code,cat_tab; 
    Close c1; 
FOR x in s_code.FIRST..s_code.LAST 
LOOP 
null;   
END LOOP; 
End_Time:= DBMS_UTILITY.GET_TIME; 
DBMS_OUTPUT.PUT_LINE('Using Bulk collect fetch time :-' ||(End_Time-Start_Time) ||' Sec'); 
END;