2016-12-03 2 views
3

Ich habe ein PL/SQL-Skript, das Datensätze von Personen (~ 4 Millionen) wiederholt und führt mehrere Updates (~ 100) und eine einzige Löschanweisung (alle diese Updates und löschen sind in verschiedenen Tabellen). Das Problem, mit dem ich konfrontiert bin, ist, dass die eine delete-Anweisung etwa die Hälfte der Laufzeit benötigt. Ich verstehe, dass wenn Sie eine Löschanweisung ausführen, muss es den Index aktualisieren, aber ich finde es ziemlich lächerlich. Ich teste gerade dieses Skript mit einem Thread unter Verwendung dbms_parallel_execute, aber ich plane, dieses Skript Multithread.Mehrere kleine löscht

Ich Ausführung eine Abfrage ähnlich der folgenden:

DELETE FROM table1 t1 
WHERE (t1.key1, t1.key2) IN (SELECT t2.key1, t2.key2 
           FROM table2 t2 
           WHERE t2.parm1 = 1234 
           AND t2.parm2 = 5678). 

folgende Fakten:

  • Table2 (~ 30 Millionen Datensätze) ist ~ 10-mal größer als table1 (~ 3 Millionen Datensätze) .
  • gibt einen Primärschlüssel für Tabelle 1 ist (Key1, Key2)
  • gibt ein Primärschlüssel auf table2 ist (Key1, Key2)
  • Es ist ein Index für Tabelle2 (parm1, parm2)
  • I haben behinderte Die Fremdschlüsseleinschränkung für Tabelle1 (Schlüssel1, Schlüssel2), die Tabelle2 referenziert (Schlüssel1, Schlüssel2)
  • Es gibt keine weiteren Einschränkungen für Tabelle1, aber viele Einschränkungen für Tabelle2.

  • Alle Auslöser für Tabelle1 haben für diese Abfrage mit geringeren Kosten aufkommt

  • Der erklären Plan deaktiviert worden als die von vielen meiner Update-Anweisungen (aber ich weiß, dass dies nicht für viel kostet Konto).

Erklären Plan Ausgabe:

OPERATION       OPTIONS                        OBJECT_INSTANCE        OBJECT_TYPE       OPTIMIZER                       SEARCH_COLUMNS        ID           PARENT_ID         DEPTH          POSITION          COST           CARDINALITY         BYTES          CPU_COST          IO_COST          TIME           
------------------------------------ ---------------------------------------------------------------------------------------------------- -------------------------------------------- ------------------------------------ ---------------------------------------------------------------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- -------------------------------------------- 
DELETE STATEMENT                                                   ALL_ROWS                                              0                       0           5           5           1           36          38043           5           1 
DELETE                                                                                                     1           0           1           1                                                                    
NESTED LOOPS                                                                                                    2           1           2           1           5           1           36          38043           5           1 
TABLE ACCESS       BY INDEX ROWID                                 2 TABLE        ANALYZED                                              3           2           3           1           4           1           25          29022           4           1 
INDEX        RANGE SCAN                                  INDEX        ANALYZED                                  1           4           3           4           1           3           1                      21564           3           1 
INDEX        UNIQUE SCAN                                  INDEX (UNIQUE)      ANALYZED                                  2           5           2           3           2           1           1           11           9021           1           1 

ich mich gefragt, ob es eine Möglichkeit gab, um diese schneller gehen zu machen löschen. Ich habe versucht, eine bulk delete zu tun, aber es schien nicht die Laufzeit zu verbessern. Wenn es irgendeine Möglichkeit gäbe, alle Löschungen auszuführen und den Index danach zu aktualisieren, vermute ich, dass es schneller laufen würde. Offensichtlich ist es nicht möglich, eine create-Tabelle aus einer Auswahl zu erstellen, da ich Datensätze (und mehrere Bedingungen durchlaufend) von einer anderen Tabelle durchlaufen lasse, um das Löschen durchzuführen.

+0

Ist Ihr Tisch zufällig index-organisiert? Versuchen Sie 'SELECT IOT_TYPE VON ALL_TABLES WHERE TABLE_NAME = 'MYTABLENAME''. Wenn das Ergebnis nicht NULL ist, ist es index-organisiert. –

+0

Das Ergebnis ist NULL für beide Tabellen. – Mocking

+1

Bitte bewahren Sie die Formatierung von der EXPLAIN-Ausgabe auf. Der Einzug ist wichtig, um ihn zu analysieren. –

Antwort

0

Ihr Aufruf zum Löschen, wobei eine Abfrage in Tabelle 2 auf 30-m-Datensätzen ausgeführt wird, die die Leistung definitiv beeinträchtigen und möglicherweise auch Sperrprobleme verursachen, die wiederum die Abfrage verlangsamen.

Ich schlage vor, Inline-Abfrage verschieben, die Daten aus Tabelle2 auswählt. Table2 sollte den Löschvorgang steuern und Kandidatensätze löschen. Es kann als Cursor ausgeführt werden oder diese Daten in temporäre Tabelle platzieren. Let delete wird in einem Block von 500, 1000 und gefolgt von Commit ausgeführt. Dieser Chunk kann basierend auf den Ergebnissen optimiert werden.

Index Update während löschen ist nicht überflüssig, wenn dieser Prozess in nicht Arbeitszeiten ausgeführt wird, können Sie Index deaktivieren und wieder neu ..

0

Ich denke also, wenn die äußere Abfrage „klein“ ist und die innere Abfrage ist "groß" - eine WHERE EXISTS kann sehr effizient sein.

Probieren Sie where exists-Klausel anstelle von In-Klausel und überprüfen Sie dann den explain-Plan und die Leistung.

DELETE FROM table1 t1 
WHERE 
Exists (select 1 
    FROM table2 t2 
    WHERE t2.parm1 = 1234 
AND t2.parm2 = 5678 
AND t2.key1 = t1.key1 
AND t2.key2 = t1.key2 
)