2017-01-11 112 views
2

這是一個疑問而不是問題。我需要從一個表中選擇一些常用字段並將其插入到不同的表中。我已經完成了2種不同風格的代碼,但都使用BULK COLLECT。 哪個更好的選擇呢,還是除了這個之外還有別的辦法嗎?PLSQL性能問題

請在下面找到必要的細節。

程序(方法1):

create or replace procedure a2 is 
    cursor c1 is select id,address from emp1; 
    type t is table of c1%rowtype; 
    c t; 
    begin 
    open c1; 
    loop 
     fetch c1 bulk collect into c; 
     exit when c.count=0; 
     forall j in 1..c.count save exceptions 
     insert into empl1(id,address) values (c(j).id,c(j).address); 
    end loop; 
    commit; 
    exception when others then 
    for j in 1..sql%bulk_exceptions.count loop 
     dbms_output.put_line('The sql error is error occured'); 
    end loop; 
    end a2; 
/

運行上述程序和輸出:

declare 
a number; 
begin 
dbms_output.put_line ('before procedure: ' || to_char(sysdate, 'HH24:MI:SS')); 
a2; 
dbms_output.put_line ('after procedure: ' || to_char(sysdate, 'HH24:MI:SS')); 
end; 

輸出:

before procedure: 23:44:48 
after procedure: 23:45:47 
PL/SQL procedure successfully completed. 

所以上述過程把59秒插入34801020記錄。

現在請找到第二個程序。

程序(方法2):

create or replace procedure a3 is 
    cursor c1 is select id,address from emp1; 
    type t is table of c1%rowtype; 
    c t; 
begin 
    select id,address bulk collect into c from emp1; 
    forall j in 1..c.count save exceptions 
    insert into empl1(id,address) values (c(j).id,c(j).address); 
exception when others then 
    for j in 1..sql%bulk_exceptions.count loop 
     dbms_output.put_line('The sql error is error occured'); 
    end loop; 
end a3; 
/

運行與輸出上面的過程。

declare 
a number; 
begin 
dbms_output.put_line ('before procedure: ' || to_char(sysdate, 'HH24:MI:SS')); 
a3; 
dbms_output.put_line ('after procedure: ' || to_char(sysdate, 'HH24:MI:SS')); 
end; 

輸出:

before procedure: 23:47:57 
after procedure: 23:48:53 
PL/SQL procedure successfully completed. 

此過程花了56秒插入34801020個記錄。

emp1表中的記錄總數。

SQL> select count(1) from emp1; 

    COUNT(1) 
    ---------- 
    34801020 

因此我的問題:

了上述兩種方法是插入300萬條記錄到表中,請建議我,如果有任何其他更好的方法做上述過程的最佳方式插入。

+3

這種類型的問題,更好地問關於[代碼審查](http://codereview.stackexchange.com/) –

+2

1)不要。 2)簡單的問題是什麼,「insert into emp1 select ..從emp1「?超過3M的記錄,每個記錄的時間差異<0.08微秒 – OldProgrammer

+1

如果你認爲CAPS在喊叫,那麼你就錯了,反正我不想在這一點上爭論,我們打算把這個程序放在一個調度程序中這樣它每隔一小時運行一次(查詢會改變)我不能在這裏添加項目代碼,如果我使用插入select的話會花費我2分多鐘 –

回答

4

我的RAN測試使用類似的代碼具有相似的數據集大小

使用遊標循環

create or replace procedure a2 is 
    cursor c1 is select empno,ename from bigemp; 
    type t is table of c1%rowtype; 
    c t; 
    begin 
    open c1; 
    loop 
     fetch c1 bulk collect into c; 
     exit when c.count=0; 
     forall j in 1..c.count save exceptions 
     insert into bigemp2(empno,ename) values (c(j).empno,c(j).ename); 
    end loop; 
    commit; 
    exception when others then 
    for j in 1..sql%bulk_exceptions.count loop 
     dbms_output.put_line('The sql error is error occured'); 
    end loop; 
    end a2; 


SQL> exec a2 

PL/SQL procedure successfully completed. 

Elapsed: 00:00:56.93 

做一個常規的插入語句,而不是使用遊標for循環

SQL> insert into bigemp2(empno, ename) 
select empno, ename from bigemp t2 


29360128 rows created. 

Elapsed: 00:00:11.30 

現在做的直接路徑插入

SQL> insert /*+ append */ into bigemp2(empno, ename) 
select empno, ename from bigemp t2 
; 


29360128 rows created. 

Elapsed: 00:00:06.01 

添加一些並行

SQL> alter session enable parallel dml; 

Session altered 

SQL> insert /*+ append parallel(2) */ into bigemp2(empno, ename) 
select /* parallel(t2, 2) */ empno, ename from bigemp t2 
; 

29360128 rows created. 

Elapsed: 00:00:03.52 

因此,在總結,僅僅通過使用合適的技術,我們可以使這個過程去量級更快(約16倍快)

+0

我只想說「更快」並不總是「更好」,取決於要求和情況。寫在HWM之上並不總是更好的方式...... – tbone

+0

@tbone你說得對,快點並不總是更好。然而,「更好」沒有被海報明確定義;但由於我們唯一認爲必須衡量的時間已經過去,所以我採取了這種方法。但即使在這個例子中,使用一個簡單的基於集合的SQL而不是一個cursor-for循環約爲5倍。 – BobC

+0

好的解釋。 +1爲你的答案 –