Ich verwalte eine Anwendung mit einem sehr großen Oracle-Datenbank-Backend (fast 1 TB Daten mit mehr als 500 Millionen Zeilen in einer Tabelle). Die Datenbank macht eigentlich gar nichts (keine SProcs, keine Trigger oder so), sie ist nur ein Datenspeicher.
Jeden Monat müssen wir Datensätze aus den beiden Haupttabellen entfernen. Die Kriterien für die Bereinigung variieren und sind eine Kombination aus Zeilenalter und einigen Statusfeldern. In der Regel werden zwischen 10 und 50 Millionen Zeilen pro Monat gelöscht (wir fügen wöchentlich etwa 3-5 Millionen Zeilen über Importe hinzu).
Derzeit müssen wir dies in Stapeln von ungefähr 50.000 Zeilen löschen (dh 50000 löschen, festschreiben, 50000 löschen, festschreiben, wiederholen). Wenn Sie versuchen, den gesamten Stapel auf einmal zu löschen, reagiert die Datenbank etwa eine Stunde lang nicht (abhängig von der Anzahl der Zeilen). Das Löschen der Zeilen in solchen Stapeln ist auf dem System sehr rau und muss in der Regel "zeitlich" über einen Zeitraum von einer Woche erfolgen. Das kontinuierliche Ausführen des Skripts kann zu einer für den Benutzer inakzeptablen Leistungsverschlechterung führen.
Ich glaube, dass diese Art des Stapellöschens auch die Indexleistung beeinträchtigt und andere Auswirkungen hat, die letztendlich zu einer Verschlechterung der Datenbankleistung führen. Es gibt 34 Indizes für nur eine Tabelle, und die Indexdatengröße ist tatsächlich größer als die Daten selbst.
Hier ist das Skript, mit dem einer unserer IT-Mitarbeiter diese Bereinigung durchführt:
BEGIN
LOOP
delete FROM tbl_raw
where dist_event_date < to_date('[date]','mm/dd/yyyy') and rownum < 50000;
exit when SQL%rowcount < 49999;
commit;
END LOOP;
commit;
END;
Diese Datenbank muss zu 99,99999% erweitert sein und wir haben nur ein 2-tägiges Wartungsfenster pro Jahr.
Ich suche nach einer besseren Methode zum Entfernen dieser Datensätze, aber ich habe noch keine gefunden. Irgendwelche Vorschläge?
quelle
Antworten:
Die Logik mit 'A' und 'B' könnte sich hinter einer virtuellen Spalte "verstecken", in der Sie die Partitionierung vornehmen können:
quelle
Die klassische Lösung hierfür ist die Partitionierung Ihrer Tabellen, z. B. nach Monat oder nach Woche. Wenn Sie sie noch nicht kennen, ähnelt eine partitionierte Tabelle mehreren identisch strukturierten Tabellen, die
UNION
bei der Auswahl implizit ausgewählt werden, und Oracle speichert automatisch eine Zeile in der entsprechenden Partition, wenn Sie sie basierend auf den Partitionskriterien einfügen. Sie erwähnen Indizes - nun, jede Partition erhält auch ihre eigenen partitionierten Indizes. Es ist eine sehr billige Operation in Oracle, eine Partition zu löschen (es ist analog zu aTRUNCATE
in Bezug auf die Auslastung, weil Sie genau das tun - eine dieser unsichtbaren Untertabellen abschneiden oder löschen). Es wird eine beträchtliche Menge an Verarbeitung sein, um "nachträglich" zu partitionieren, aber es macht keinen Sinn, über verschüttete Milch zu weinen - die Vorteile, die dies bisher mit sich bringt, überwiegen die Kosten. Jeden Monat teilen Sie die oberste Partition, um eine neue Partition für die Daten des nächsten Monats zu erstellen (Sie können dies einfach mit einem automatisierenDBMS_JOB
).Und mit Partitionen können Sie auch die Beseitigung paralleler Abfragen und Partitionen ausnutzen , was Ihre Benutzer sehr glücklich machen sollte ...
quelle
A
wennDateA
älter als 3 Jahre" ist, wird er gelöscht. Wenn der Status istB
undDateB
ist älter als 10 Jahre, wird es gelöscht. Wenn ich die Partitionierung richtig verstehe, wäre die Partitionierung in einer solchen Situation nicht sinnvoll (zumindest was die Bereinigung betrifft).Ein zu berücksichtigender Aspekt ist, wie viel von der Löschleistung von Indizes und wie viel von der Basistabelle herrührt. Jeder aus der Tabelle gelöschte Datensatz erfordert dasselbe Löschen der Zeile aus jedem Btree-Index. Wenn Sie mehr als 30 Btree-Indizes haben, wird vermutlich der größte Teil Ihrer Zeit für die Indexpflege aufgewendet.
Dies hat Auswirkungen auf die Nützlichkeit der Partitionierung. Angenommen, Sie haben einen Index zum Namen. Ein Standard-Btree-Index, der sich alle in einem Segment befindet, muss möglicherweise vier Sprünge ausführen, um vom Stammblock zum Blattblock zu gelangen, und einen fünften Lesevorgang, um die Zeile zu erhalten. Wenn dieser Index in 50 Segmente unterteilt ist und Sie den Partitionsschlüssel nicht als Teil der Abfrage haben, muss jedes dieser 50 Segmente überprüft werden. Jedes Segment ist kleiner, so dass Sie möglicherweise nur zwei Sprünge ausführen müssen, am Ende jedoch möglicherweise 100 statt der vorherigen fünf Lesevorgänge.
Wenn es sich um Bitmap-Indizes handelt, unterscheiden sich die Gleichungen. Sie verwenden wahrscheinlich keine Indizes, um einzelne Zeilen zu identifizieren, sondern Sätze von ihnen. Anstelle einer Abfrage mit 5 E / A-Vorgängen zum Zurückgeben eines einzelnen Datensatzes wurden 10.000 E / A-Vorgänge verwendet. Daher spielt der zusätzliche Aufwand für zusätzliche Partitionen für den Index keine Rolle.
quelle
Das Löschen von 50 Millionen Datensätzen pro Monat in Chargen von 50.000 entspricht nur 1000 Iterationen. Wenn Sie alle 30 Minuten 1 löschen, sollte dies Ihrer Anforderung entsprechen. Eine geplante Aufgabe zum Ausführen der von Ihnen bereitgestellten Abfrage, zum Entfernen der Schleife, damit sie nur einmal ausgeführt wird, sollte keine spürbare Beeinträchtigung der Benutzer verursachen. Wir machen ungefähr das gleiche Volumen an Aufzeichnungen in unserer Produktionsstätte, das fast rund um die Uhr läuft und unseren Anforderungen entspricht. Tatsächlich verteilen wir alle 10 Minuten etwas mehr als 10.000 Datensätze, die in etwa 1 oder 2 Sekunden auf unseren Oracle-Unix-Servern ausgeführt werden.
quelle
Wenn der Speicherplatz nicht knapp ist, können Sie möglicherweise eine Arbeitskopie der Tabelle
my_table_new
erstellen , z. B. mithilfe von CTAS (Create Table As Select) mit Kriterien, bei denen die zu löschenden Datensätze nicht berücksichtigt werden. Sie können die create-Anweisung parallel und mit dem append-Hinweis ausführen, um sie zu beschleunigen, und dann alle Ihre Indizes erstellen. Benennen Sie anschließend die vorhandene Tabelle in ummy_table_old
und benennen Sie die Tabelle "work" in um , sobald sie fertig ist (und getestet wurde)my_table
. Sobald Sie mit allemdrop my_table_old purge
vertraut sind, können Sie den alten Tisch loswerden. Wenn es eine Reihe von Fremdschlüsseleinschränkungen gibt, schauen Sie sich dasdbms_redefinition
PL / SQL-Paket an . Es wird Ihre Indizes, Beschränkungen usw. klonen, wenn Sie die entsprechenden Optionen verwenden. Dies ist eine Zusammenfassung eines Vorschlags von Tom Kyte von AskTomRuhm. Nach der ersten Ausführung können Sie alles automatisieren, und die Erstellung der Tabelle sollte viel schneller vonstatten gehen. Dies kann bei laufendem System erfolgen, und die Ausfallzeit der Anwendung ist auf weniger als eine Minute für das Umbenennen der Tabellen begrenzt. Die Verwendung von CTAS ist viel schneller als mehrere Batch-Löschvorgänge. Dieser Ansatz kann besonders nützlich sein, wenn Sie keine lizenzierte Partitionierung haben.Beispiel-CTAS, in dem Zeilen mit Daten der letzten 365 Tage gespeichert werden und
flag_inactive = 'N'
:quelle
Wenn Sie eine Partition löschen, lassen Sie globale Indizes unbrauchbar, die neu erstellt werden müssen. Die Neuerstellung globaler Indizes wäre ein großes Problem. Wenn Sie dies online tun, ist dies recht langsam. Andernfalls benötigen Sie Ausfallzeiten. In beiden Fällen kann nicht für die Anforderung passen.
"Normalerweise werden zwischen 10 und 50 Millionen Zeilen pro Monat gelöscht."
Ich würde empfehlen, mit PL / SQL Batch löschen, mehrere Stunden ist ok, denke ich.
quelle