Optimierung der Abfrage Löschen mit einer großen Anzahl von Daten auf oracle
Arbeite ich auf oracle 9i. Ich habe eine Tabelle mit 135,000,000 records, partitioniert, wobei jede partition mit ca. Zu 10.000.000 Zeilen. alle indizierten und alles.
Muss ich löschen um 70,000,000 Zeilen aus dieser die neue business-Anforderung.
So habe ich eine Sicherung der zu löschenden Zeilen als separate Tabelle.
Table1 <col1, col2........> -- main table (135,000,000 rows)
Table2 <col1, col2........> -- backup table (70,000,000 rows)
Versucht, die unterhalb Abfrage löschen.
Delete from table1 t1 where exists (select 1 from table2 t2 where t2.col1 = t1.col1)
aber es dauert unendlich Stunden.
dann versucht
declare
cursor c1 is
select col1 from table2;
c2 c1%rowtype;
cnt number;
begin
cnt :=0;
open c1;
loop
fetch c1 into c2;
exit when c1%notfound;
delete from table1 t1 where t1.col1 = c2.col1;
if cnt >= 100000 then
commit;
end if;
cnt:=cnt+1;
end loop;
close c1;
end;
sogar noch seine schon seit mehr als 12 Stunden. und immer noch nicht abgeschlossen.
Bitte beachten Sie, dass es mehrere Indizes auf Tabelle1 und ein index über col1 auf Tabelle2. alle Tabellen und Indizes werden analysiert.
Bitte beraten, ob es eine Möglichkeit der Optimierung für dieses Szenario.
Danke Jungs.
- Wenn der code wirklich so aussieht, das Sie Begehen werden, für jede Zeile nach Zeile 100000, das ist wahrscheinlich nicht das, was Sie wollen und werden langsam natürlich. Stellen Sie Ihre cnt:=0 nach dem commit
- Ya-Zähler zurücksetzen muss, ich glaube, das war ein Tippfehler ausgelassen. Aber ich zog es vor, fallen die Indizes und simulieren, wie die top-Antwort
Du musst angemeldet sein, um einen Kommentar abzugeben.
Löschen aller Indizes (Sicherung der create-Anweisungen)
Verwenden Sie die select-Anweisung, die verwendet wird, um die backup-Tabelle, erstellen Sie einen Befehl LÖSCHEN
Neu alle index
Ich erinnere mich, vor diesem Problem früher. In diesem Fall Griffen wir, um dies zu tun, da lief es schneller als alle anderen zu löschen-operation:
1) Erstellen Sie eine andere Tabelle mit der gleichen Struktur
2) Einfügen in die neue Tabelle die Datensätze, die Sie behalten möchten (verwenden Sie den Direkten Pfad einfügen, um diese Fahrt)
3) Fallen die alte Tabelle
4) Benennen Sie die neue Tabelle
Sagen Sie, dass die Tabelle partitioniert ist. Ihre Absicht, die fallen alle Daten, die in bestimmten Partitionen? Wenn dem so ist, sollten Sie in der Lage, ziehen Sie einfach die 7 Partitionen, die die 70 Millionen Zeilen, die Sie löschen möchten. Ich nehme jedoch an, dass Ihr problem ist nicht so einfach.
Wenn Sie tun können interim verpflichtet, dass bedeutet, dass Sie kümmern sich nicht um die transaktionskonsistenz, die meisten effizienter Ansatz ist wahrscheinlich etwas entlang der Linien von
Abgesehen, dass anstatt der backup-Tabelle, wäre es effizienter, einfach die
DELETE
AnweisungKönnen Sie auch profitieren von dem löschen oder deaktivieren von Indizes und Einschränkungen vor dem ausführen des
DELETE
.Werde ich beantworten diese Annahme, dass es billiger ist, filter gegen die backup-Tabelle, aber es wäre wahrscheinlich billiger, nur die negation der Kriterien, die Sie verwendet, zum Auffüllen der backup-Tabelle.
1) erstellen Sie eine neue Tabelle mit der gleichen Struktur. Keine Indizes, constraints, Trigger.
2)
3) zu überprüfen, und führen Sie das Ergebnis der vorherigen Abfrage
4) bauen Sie die Indizes, Einschränkungen und Trigger, die, wenn nötig
Dies vermeidet massive Mengen von redo-und undo im Vergleich zu den "löschen".
append-Hinweis für direct-path inserts
keine Protokollierung zur weiteren Reduzierung redo - stellen Sie sicher, dass Sie backup danach
nutzt Ihr Partitionierung zu brechen, die die Arbeit in Blöcken, die sortiert werden können, weniger geht
Könnten Sie wahrscheinlich schneller gehen mit parallel-Einsatz + parallel wählen, aber es ist wahrscheinlich nicht nötig. Nur nicht parallel select ohne den insert-und ein "alter session enable parallel dml"
nologging
ist kein echter Hinweis, Sie müssen nurappend
.