2017-01-11 13 views
2

Dies ist eher ein Zweifel als ein Problem. Ich habe die Anforderung, nur einige der allgemeinen Felder aus einer Tabelle auszuwählen und sie in eine andere Tabelle einzufügen. Ich habe den Code mit 2 verschiedenen Stilen gemacht, aber beide mit BULK COLLECT. Welches ist die bessere Option zu gehen oder gibt es einen anderen Weg abgesehen von diesem?PLSQL-Leistungsproblem

Hier finden Sie die notwendigen Details.

Verfahren (Weg 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; 
/

Ausführen des obigen Verfahrens und Ausgang:

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; 

Ausgang:

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

So das obige Verfahren 59 Sekunden nahm 34.801.020 einfügen Aufzeichnungen.

Jetzt finden Sie das zweite Verfahren.

Verfahren (Weg 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; 
/

Ausführen des obigen Verfahrens mit Ausgang.

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; 

Ausgang:

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

Diese Prozedur 56 Sekunden nahm 34.801.020 Datensätze einzufügen.

Gesamtdatensätze in Emp1-Tabelle.

SQL> select count(1) from emp1; 

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

Daher meine Frage:

Welche der beiden oben genannten Methoden der beste Weg ist, die Tabelle einfügen 3 Millionen Datensätze in und bitte mir vorschlagen, wenn es eine andere bessere Weg ist, den obigen Prozess zu tun von Einfügen.

+3

Diese Art von Fragen ist besser gefragt auf [Code Review] (http://codereview.stackexchange.com/) –

+2

1) nicht schreien. 2) Was ist falsch mit einfach, "in Emp1 einfügen ..von ang1" ? Aufzeichnungen über 3M, ist die Zeitdifferenz pro Datensatz <0,08 Mikrosekunden. – OldProgrammer

+1

Wenn u CAPS denken dann schreit u falsch sind. Sowieso nicht wollen, um i zu diesem Punkt streiten. Wir werden diese Verfahren in einem Scheduler setzen einmal so, dass es jede Stunde ausgeführt wird. (die Abfrage ändern würde) ich nicht den Projektcode hier hinzufügen kann. wenn ich einfügen in ausgewählten verwenden ist mir mehr als 2 Minuten. –

Antwort

4

Rans ich einen Test ein ähnliches Stück Code mit einer ähnlichen Datensatz Größe

Mit einer Cursor Schleife

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 

Doing eine regulären Einsatz Anweisung, keine Cursor-for-Schleife

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


29360128 rows created. 

Elapsed: 00:00:11.30 

tun nun ein direkter Weg einfügen

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


29360128 rows created. 

Elapsed: 00:00:06.01 
In

einig Parallelität

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 

Also zusammenfassend, nur durch die entsprechende Technik, können wir den Prozess gehen und um eine Größenordnung schneller (ca. 16x schneller)

+0

Ich würde nur bemerken, dass "schneller" nicht immer "besser" ist, hängt von den Anforderungen und der Situation ab. Schreiben über die HWM ist nicht immer der bessere Weg ... – tbone

+0

@tbone Sie haben Recht, dass schneller nicht immer besser ist. "Besser" wurde vom Poster jedoch nicht explizit definiert; aber da das einzige Denken, das wir messen mussten, die verstrichene Zeit war, entschied ich mich für diesen Ansatz. Aber selbst für dieses Beispiel war die Verwendung einer einfachen set-basierten SQL statt einer Cursor-for-Schleife etwa 5x fater. – BobC

+0

Schöne Erklärung. +1 für Ihre Antwort –