Ich werde nachlässig: auf der Suche nach meiner Zusammenfassung der ersten beiden Teile von Jonathan Lewis AllThingsOracle-Serie zu Massendatenlöschungen ist mir aufgefallen, dass ich dazu keine Zusammenfassungen geschrieben habe. Aber das lässt sich ja ändern:
Massive Deletes – Part 1: beschäftigt sich zunächst mit strategischen und taktischen Fragen bei der Löschung von Massendaten. Auf der strategischen Ebene liegen Fragen nach der Zielsetzung der Löschung: was verspricht man sich davon und lohnt sich der Aufwand überhaupt und schafft die Löschung nicht vielleicht neue Probleme. Auf taktischer Ebene liegen Fragen der Verfügbarkeit von Ressourcen, der Möglichkeit einer Downtime zu Wartungszwecken etc. Dazu liefert der Autor zwei Szenarien in denen Partitioninierung - bzw. ihr Fehlen - und globale Indizes eine Rolle spielen. Ausgehend davon werden zwei übliche Gründe für Löschungen und drei Standard-Muster aufgeführt. Die Gründe sind:
- Verbesserung der Perfromance
- Reduzierung der Storage-Verwendung
Bei den Pattern werden folgende Fälle aufgeführt:
- Löschung von Daten auf Basis einer Eingangszeit
- Löschung von Daten auf Basis des Endzeitpunkts der Bearbeitung
- Löschung der Daten einer bestimmten Kategorie
In Zusammenhang mit diesen Mustern steht die Frage, wie Oracle die Daten auf Blockebene speichert. Dabei führt die "Löschung von Daten auf Basis einer Eingangszeit" dazu, dass komplette Blöcke in den ersten Extents einer Tabelle frei werden, die dann wieder von (erneut gut geclusterten) neuen Daten belegt werden. Bei den beiden anderen Mustern kann sich die physikalische Clusterung der Daten deutlich verändern, da die "Löschung der Daten einer bestimmten Kategorie" vermutlich aus allen Blöcken etwa den gleichen Anteil entfernt, während bei der "Löschung von Daten auf Basis des Endzeitpunkts der Bearbeitung" eine gewisse Korrelation zur zeitlichen Entwicklung vorliegt,die aber weniger stark ist als bei den Eingangszeitpunkten. Diese physikalische Clusterung der Daten kann sich dann wieder massiv auf die Effektivität von Indizes auswirken (Stichwort: clustering factor). Außerdem spielt die Menge der Indizes natürlich eine große Rolle bei der Löschung selbst, da diese Indizes während der Löschung verwaltet werden müssen.
Massive Deletes – Part 2: beginnt mit der Beobachtung, dass die Frage, wo massive Datenlöschungen beginnen, angesichts sehr unterschiedlicher Hardware schwer zu definieren ist. Im Beispiel wird eine Tabelle von 1,6G erzeugt, die 10M rows für 10 Jahre enthält (1M pro Jahr). Auf dieser Basis werden die drei im ersten Teil skizzierten Szenarien durchgespielt. Die Effekte der Löschung werden mit einer Query überprüft, die über die Anzahl der rows pro Block gruppiert. Für die "Löschung von Daten auf Basis einer Eingangszeit" ergeben sich auch nach der Löschung sehr dicht gepackte Blöcke. Für die Variante "Löschung von Daten auf Basis des Endzeitpunkts der Bearbeitung" bleiben relativ viele Blöcke mit einem deutlich niedrigeren Füllgrad stehen, von denen allerdings die überwiegende Mehrheit nicht für neue Inserts verwendet werden würden. Auch für die Indizes ergibt sich ein ähnliches Bild - allerdings ist die zugehörige Analyse-Query deutlich komplexer: jedenfalls wird der Füllgrad der Indizes der Indizes reduziert. Abhängig von der Verteilung der Einträge kann die Maintenance bei der Löschung sehr teuer werden, so dass es unter Umständen sinnvoller sein könnte, den Index vor der delete Operation als unusable zu markieren (oder zu löschen) und anschließend neu aufzubauen.
Massive Deletes – Part 3: erläutert die Bereiche, in denen eine Löschung - wie jede andere DML-Operation - einen Overhead hervorruft, und da der Herr Lewis das sehr präzise zusammenfasst, zitiere ich hier extensiv:
- redo: "every change to a data block generates redo – a description of the new information that has been written to the block plus an overhead of a few tens of bytes: and if you’ve got four indexes on the table then you may be changing 5 blocks for every row you delete."
- undo: "Every time you delete a row you “preserve” the row by writing into the undo segment a description of how to re-insert that row, and how to “undelete” the index entries. Each undo entry has an overhead of a few tens of bytes and each undo entry IS a change to a data block so (redo second thoughts) generates even more redo. Combining the two sources of redo, a single row delete with four affected indexes could produce around 1KB of redo, plus the size of the row and index entries deleted."
- I/O effects: hier kürze ich ab: Blöcke müssen von der Platte und in den Cache gelesen werden - und umgekehrt wieder geschrieben.
- Concurrency: auch hier versuche ich's mit Verkürzung: aufgrund Oracles MVCC-Verfahrens muss mit zusätzlichen redo und undo Effekten gerechnet werden.
Weiterhin wird erklärt, dass die Optimizer-Kosten eines delete denen eines entsprechenden select rowid from ... entsprechen. Für das delete hat der Optimizer im gegebenen Fall die Auswahl zwischen drei Strategien: FULL TABLE SCAN, INDEX FAST FULL SCAN (der aber erst seit 12c ohne Hint-Verwendung berücksichtigt wird) und INDEX RANGE SCAN. In zwei Beispielen wird nun ausgeführt, wie die Ressourcen-Nutzung in Hinsicht auf redo und undo für verschiedene Zugriffs-Varianten aussieht (abhängig von der Anzahl der vorhandenen Indizes) - einmal für eine Löschung gut geclusterter Daten und einmal für Daten, die stark verteilt sind. Interessant ist dabei vor allem folgender Punkt:
It’s not a well-known phenomenon, but Oracle uses a completely different strategy for deleting through an index range/full scan from the strategy it uses when delete through a tablescan or index fast full scan. For the tablescan/index fast full scan Oracle deletes a row from the table then updates each index in turn, before moving on to delete the next row. For the index range scan / full scan Oracle deletes a table row but records the rowid and the key values for each of the indexes that will need to be updated – then carries on to the next row without updating any indexes. When the table delete is complete Oracle sorts all the data that it has accumulated by index, by key, and uses bulk updates to do delayed maintenance on the indexes. Since bulk updates result in one undo record and one redo change vector per block updated (rather than one per row updated) the number of redo entries can drop dramatically with a corresponding drop in the redo and undo size.
Insofern kann die Löschung über die den Index hinsichtlich der Index-Maintenance also grundsätzlich effizienter sein als die Verwendung von FTS (bzw. dem eng verwandten IFFS). Allerdings erfordert der Index Range Scan (bzw. der verwandte Index Full Scan) zusätzliche Sortierungen. Für die unterschiedlichen Pattern ergibt sich dabei jeweils eine sehr unterschiedliche Effektivität der Verfahren: während für die gut geclusterten Daten der Index Range Scan sehr performant erfolgt, ist bei den in der Tabelle stark verteilten Daten der FTS die bessere Wahl. Dabei ist die Arbeit zur Änderung der Tabelle unter Umständen im einen Fall höher, während die Index-Maintenance in diesem Fall höher wird und umgekehrt. Weniger gut schneidet in vielen Fällen der Index Fast Full Scan, der in 12c unter Umständen sehr häufig ausgewählt werden kann, weil er für select rowid from ... Queries eine sehr günstige Wahl ist.
Da Jonathan Lewis im dritten Artikel bereits weitere Beiträge angekündigt hat, werde ich hier vermutlich später noch Ergänzungen vornehmen.
Keine Kommentare:
Kommentar veröffentlichen