Auf der DeDUG – der deutschen Db2 User Group, die ich organisiere – kam eine interessante Fragestellung auf, die ich in diesem Blog-Artikel beleuchten möchte.
In einem Data Warehouse soll die Verfügbarkeit von Data Marts verbessert werden. Daten kommen immer später an und so reicht oft die Nacht nicht mehr aus, die Daten zu verarbeiten, da die ETL-Prozesse nur limitiert weiter optimierbar sind. Im genannten Szenario wurden die Tabellen immer komplett geladen – also nicht per Delta-Beladung, was ich generell empfehlen würde. Auch zu diesen Herausforderungen könnte man sicherlich auch mindestens einen Artikel verfassen.
Es wurde also nach einer guten Möglichkeit gesucht, zwischen zwei Tabellen hin- und her zuschalten, sobald eine Beladung fertiggestellt ist. Dabei sollte dies ohne DDL und große Ausfallzeit möglich sein.
Neue Ansätze
Schon im User Group Meeting wurden so einige Ansätze diskutiert. Drop und Create droppt auch alle Rechte und noch mehr und auch ein Rename müsste öfter durchgeführt werden und kommt eben nicht ohne DDL aus. Eine Load-Operation sperrt die Tabelle und sorgt somit für die unerwünschte Unterbrechung der Verfügbarkeit.
Mein Vorschlag geht von folgender Konstellation aus:
- Es werden zwei gleichartige Tabellen angelegt, in der Struktur der Zieltabelle
- Es wird eine weitere Control-Tabelle angelegt, die festlegt, welche der beiden Tabellen die aktive ist
- Über die beiden Zieltabellen wird eine UNION ALL View gelegt, die je nach Eintrag der Control-Tabelle nur die Daten der jeweiligen Tabelle zurückgibt.
Mit diesem Ansatz ist für die Umschaltung kein DDL nötig und die Umschaltung erfolgt durch einen einfachen Update der Control-Tabelle. Um sich das besser vorstellen zu können, bauen wir dieses Szenario einfach einmal auf:
Auf die gleiche Art und Weise wird die Tabelle LINEITEM2 identisch angelegt.
Zusätzlich wird die Control-Tabelle angelegt.
Durch den INSERT wird die LINEITEM1 aktiv gesetzt. Für die Strukturierung der CONTROL-Tabelle gibt es natürlich alternative Möglichkeiten.
Das Herzstück der Lösung ist die UNION ALL View, die folgendermaßen anzulegen ist:
Der Join stellt sicher, dass immer nur ein Teil des UNION ALL zurückgegeben wird – eben genau der Inhalt der Tabelle, die in der CONTROL-Tabelle als „tableactive“ angegeben ist.
Warum UNION ALL und nicht einfach ein UNION?
Das hat ganz klar einen Performance-Hintergrund – der UNION dedupliziert Daten und benötigt dafür einen Sort und das kostet Zeit.
Funktional läuft diese Lösung sauber, aber technisch sollte man auch prüfen, ob der Optimizer den Zugriffsweg und die Statistiken sauber erkennt.
Hier zeigt sich, dass der Optimizer die Datenmengen aus beiden Tabellen addiert und so die Filterung über die Control-Tabelle nicht mitbekommt. Das könnte zu sub-optimalen Zugriffswegen führen.
Um solche Fehleinschätzungen in den Griff zu bekommen, gibt es Statistical Views, mit deren Hilfe man dem Optimizer zusätzliche Statistiken auch über Joins mitteilen kann, indem man auf diese RUNSTATS ausführt. Abbildung 5 zeigt dieses Vorgehen. Details dazu finden Sie auch in der Db2 Dokumentation der IBM.
Der Explain zeigt nach diesem Vorgehen folgendes
Die Statistiken werden korrekt gebildet – somit steht dieser Lösung nun nichts mehr entgegen. Nach dem Umschalten der CONTROL-Tabelle muss nur noch an den Runstats auf beide Statistical Views gedacht werden, aber diesen Schritt kann man auch in die ETL-Verarbeitung legen und dort automatisieren.
Viel Erfolg bei der Anwendung und wenn Sie andere oder weitere Herausforderungen in Ihrem Data Warehouse haben – dann unterstütze ich Sie gerne. Zur Kontaktaufnahme schreiben Sie mir bitte eine Mail an michael.tiefenbacher@mip.de