2016-05-20 4 views
0

Ich muss fast 60k Datensätze einer Oracle-Tabelle über eine gespeicherte Prozedur verarbeiten. Die Verarbeitung besteht darin, dass ich für jede solche Zeile eine Zeile in einer zweiten Tabelle löschen und aktualisieren und eine Zeile in eine dritte Tabelle einfügen muss.Oracle Bulk Collect mit Limit und für alle, die nicht alle Datensätze korrekt verarbeiten

Mit Cursor-Looping dauert der Vorgang etwa 6-8 Stunden. Wenn ich zu Bulk Collect with Limit wechsle, wird die Ausführungszeit reduziert, aber die Verarbeitung ist nicht korrekt. Im Anschluss ist die Masse sammelt Version des Verfahrens

create or replace procedure myproc() 
is 
    cursor c1 is select col1,col2,col3 from tab1 where col4=3; 
    type t1 is table of c1%rowtype; 
    v_t1 t1; 
begin 
    open c1; 
    loop 
     fetch c1 bulk collect into v_t1 limit 1000; 
     exit when v_t1.count=0; 
     forall i in 1..v_t1.count 
      delete from tab2 where tab2.col1=v_t1(i).col1; 
     commit; 
     forall i in 1..v_t1.count 
      update tab2 set tab2.col1=v_t1(i).col1 where tab2.col2=v_t1(i).col2; 
     commit; 
     forall i in 1..v_t1.count 
      insert into tab3 values(v_t1(i).col1,v_t1(i).col2,v_t1(i).col3); 
     commit; 
    end loop; 
    close c2; 
end; 

Für rund 20k diese Aufzeichnungen, der erste Löschvorgang korrekt bearbeitet, jedoch nachfolgende Aktualisierung und einfügen wird nicht verarbeitet. Für die verbleibenden 40.000 Datensätze werden alle drei Operationen korrekt verarbeitet.

Fehle ich etwas? Was ist der maximale LIMIT-Wert, den ich mit Bulk Collect verwenden kann?

+0

So wissen Sie über die Hauptschleife 60 mal durchlaufen, und Sie wissen, dass Sie 60k Löschungen aber 40k Updates tun und Einsätze? Wie prüfen/zählen Sie? –

+0

Die Tabelle tab3 ist eine Protokolltabelle, die vor der Ausführung der Prozedur gelöscht wird. Wenn also nach Ausführung der Prozedur 40k Datensätze in dieser Tabelle vorhanden sind, bedeutet dies, dass 40k-Einträge erfolgreich waren. Die Tabelle (tab1) hat fast 2 * 60k Datensätze vor der Ausführung der Prozedur und nach der Ausführung ist die Anzahl der Datensätze 60k, was bedeutet, 60k Löschungen waren erfolgreich. –

+0

OK, also ist tab2.col1 einzigartig? Ich versuche nicht, schwierig zu sein, versuche nur zu denken, was du vielleicht übersehen hast. –

Antwort

0

Sie sollten versuchen, mit SAVE AUSNAHMEN Klausel FORALL-, so etwas wie (nicht getestet):

create or replace procedure myproc 
as 
    cursor c1 is select col1,col2,col3 from tab1 where col4=3; 
    type t1 is table of c1%rowtype; 
    v_t1 t1; 
    dml_errors EXCEPTION; 
    PRAGMA exception_init(dml_errors, -24381); 
    l_errors number; 
    l_errno number; 
    l_msg varchar2(4000); 
    l_idx number; 
begin 
    open c1; 
    loop 
     fetch c1 bulk collect into v_t1 limit 1000; 
     -- process v_t1 data 
     BEGIN 
      forall i in 1..v_t1.count SAVE EXCEPTIONS 
       delete from tab2 where tab2.col1=v_t1(i).col1; 
      commit; 
     EXCEPTION 
      when DML_ERRORS then 
       l_errors := sql%bulk_exceptions.count; 
       for i in 1 .. l_errors 
       loop 
        l_errno := sql%bulk_exceptions(i).error_code; 
        l_msg := sqlerrm(-l_errno); 
        l_idx := sql%bulk_exceptions(i).error_index; 
        -- log these to a table maybe, or just output 
       end loop; 
     END; 

     exit when c1%notfound; 
    end loop; 
    close c2; 
end; 
+1

Sie wollen also sagen, diese 20k-Datensätze werden nicht bearbeitet, wegen einer Ausnahme, die ich fangen und protokollieren/drucken muss, um das Problem zu debuggen? Aber wenn es tatsächlich eine Ausnahme gibt, sollte nicht Toad (wo ich den gespeicherten Proc ausführe) mir die Nachricht geben und die Ausführung abrupt beenden? –

+0

Nein, ich sage nur, dass es hilfreich ist beim Debuggen was passiert. Wir haben keine spezifischen Daten, also raten wir ein bisschen. Es ist auch möglich, dass Sie nicht so viele Zeilen aktualisieren/einfügen, wie Sie denken, nicht unbedingt, dass die Operation nicht ausgeführt wird (sie kann die Anweisung ausführen und 0 Zeilen einfügen oder aktualisieren). Um das zu wissen, fügen Sie SQL% ROWCOUNT unmittelbar nach jeder Forall-Anweisung hinzu. – tbone

Verwandte Themen