CiAgICA8IS0tIExpbmtlZEluIC0tPgogICAgPHNjcmlwdCB0eXBlPSJ0ZXh0L2phdmFzY3JpcHQiPgogICAgICAgIF9saW5rZWRpbl9wYXJ0bmVyX2lkID0gIjEyMzUwNzMiOwogICAgICAgIHdpbmRvdy5fbGlua2VkaW5fZGF0YV9wYXJ0bmVyX2lkcyA9IHdpbmRvdy5fbGlua2VkaW5fZGF0YV9wYXJ0bmVyX2lkcyB8fCBbXTsKICAgICAgICB3aW5kb3cuX2xpbmtlZGluX2RhdGFfcGFydG5lcl9pZHMucHVzaChfbGlua2VkaW5fcGFydG5lcl9pZCk7CiAgICA8L3NjcmlwdD48c2NyaXB0IHR5cGU9InRleHQvamF2YXNjcmlwdCI+CiAgICAgICAgKGZ1bmN0aW9uKCl7dmFyIHMgPSBkb2N1bWVudC5nZXRFbGVtZW50c0J5VGFnTmFtZSgic2NyaXB0IilbMF07CiAgICAgICAgICAgIHZhciBiID0gZG9jdW1lbnQuY3JlYXRlRWxlbWVudCgic2NyaXB0Iik7CiAgICAgICAgICAgIGIudHlwZSA9ICJ0ZXh0L2phdmFzY3JpcHQiO2IuYXN5bmMgPSB0cnVlOwogICAgICAgICAgICBiLnNyYyA9ICJodHRwczovL3NuYXAubGljZG4uY29tL2xpLmxtcy1hbmFseXRpY3MvaW5zaWdodC5taW4uanMiOwogICAgICAgICAgICBzLnBhcmVudE5vZGUuaW5zZXJ0QmVmb3JlKGIsIHMpO30pKCk7CiAgICA8L3NjcmlwdD4KICAgIDxub3NjcmlwdD4KICAgICAgICA8aW1nIGhlaWdodD0iMSIgd2lkdGg9IjEiIHN0eWxlPSJkaXNwbGF5Om5vbmU7IiBhbHQ9IiIgc3JjPSJodHRwczovL3B4LmFkcy5saW5rZWRpbi5jb20vY29sbGVjdC8/cGlkPTEyMzUwNzMmZm10PWdpZiIgLz4KICAgIDwvbm9zY3JpcHQ+CiAgICA8IS0tIEVuZCBMaW5rZWRJbiAtLT4KICAgIA==
Generic filters
Exact matches only
Search in title
Search in excerpt
Search in content

ETL inkrementell, Verfahren von SQL-Server für inkrementelle Ladeszenarien

Unser Standard-Modell eines ETL-Prozesses, so wie es auch durch DeltaMaster Modeler unterstützt wird, ist darauf optimiert, jede Nacht sämtliche Daten des OLAP-Modells erst in ein relationales Snowflake-Schema zu laden und danach daraus die OLAP-Datenbank vollständig zu prozessieren. Beim vollständigen Prozessieren werden alle Daten der OLAP-Datenbank gelöscht und aus den Snowflake-Dateien neu geladen. Dieses Vorgehen ist bei den vielen Anwendungen optimal, da den Anwendern täglich aktuelle Daten genügen, des Nachts genug Zeit für den Ladeprozess ist und wegen eines hohen Optimierungsgrades selbst recht große Datenmengen jede Nacht geladen werden können.

Meine Erfahrung aus Projekten zeigt jedoch, dass es auch Umstände gibt, unter denen dieses System des vollständigen Ladens nicht optimal ist: Zum einem gibt es durchaus Systeme, in denen die Datenmenge so hoch ist, sodass sie nicht mehr in einer Nacht vollständig geladen werden kann.

Immer öfter werden in Projekten aber auch Systeme entwickelt, in denen die relationale Datenbank nicht mehr nur als Transfer-Medium genutzt wird. Es entstehen Hybrid-Systeme, in denen sowohl die relationale als auch die multidimensionale Datenbank zur Dateneingabe und zum Reporting genutzt wird. Planungsprojekte sind dafür ein sehr gutes Beispiel. In solchen Umgebungen steigt der Bedarf nach einem untertägigen Abgleich.

Im Idealfall wird dem Anwender immer weniger bewusst, ob er nun gerade auf der relationalen Datenbank arbeitet oder multidimensional. Ladeprozesse, die z.B. jede Minute laufen (sehr häufige Ausführung) oder immer bei einer Eingabe in eine relationale Tabelle (ereignisgesteuert) und nur wenige zehntel Sekunden dauern, wären dafür notwendig. Die redundante Datenhaltung wird in Kauf genommen, wenn man dafür die Vorteile von multidimensionaler und relationaler Datenbank optimal kombinieren kann.

Der Ladeprozess sollte dann a) möglichst wenig Ressourcen nutzen und b) nicht allzu lange dauern, da ja auch während des Abgleichs die Chance hoch ist, dass neue Eingaben gemacht werden. Die Aufgabe erscheint dann als durchaus lösbar, wenn man bedenkt, dass diese Ladevorgänge sehr häufig hintereinander ausgeführt werden und das Datendelta entsprechend gering sein wird.

In solchen Fällen sollte von der vollständigen Erstellung von Snowflake und OLAP-Datenbank abgesehen werden und nur speziell die Datensätze bearbeitet werden, die sich seit dem letzten ‚transform’ in irgendeiner Weise geändert haben. Sowohl der relationale Teil, also der SQL-Server, als auch die multidimensionalen Analysis Services bieten Techniken an, welche das inkrementelle Laden unterstützen. Diese sollen hier kurz vorgestellt werden.

Durch zusätzliche Spalten in denen Informationen über die letzte Änderung (Änderungszeit) abgelegt wird, könnte man die seit des letzten ‚transforms’ geänderten Datensätze herausfinden. Dieses manuelle Verfahren birgt jedoch einige Tücken. Außerdem ist dies ein so allgemeines Thema im Datenbankumfeld, dass von SQL-Server selbst 2 Mechanismen zur Verfügung gestellt werden, die genau diese Problematik bedienen: CT (Change Tracking oder Änderungsnachverfolgung) und CDC (Change Data Capture).

In der multidimensionalen Datenbank gibt es zum einen die Möglichkeit, OLAP-Objekten (wie Dimensionen, Measuregruppen usw.) nur neue Datensätze hinzuzufügen (Process Add) oder nur geänderte Datensätze zu bearbeiten (Process Update). Alternativ kann auf die vielfältigen Varianten des proaktiven Caching zugegriffen werden.

CT (Änderungsnachverfolgung)

Zentraler Bestandteil eines Change Tracking ist die Datenbankversion. Diese Nummer erhöht sich inkrementell, sobald Daten in den am Change Tracking teilhabenden Tabellen geändert werden (Update, Delete oder Insert). Jeder Zeile wird die Datenbankversion zugeordnet, in der sich die Zeile zum letzten Mal geändert hat. So können die geänderten Datensätze schnell gefunden werden, sofern man die Datenbankversion des letzten ‚transform’ kennt.

Eine Datenbank, in der das Change Tracking genutzt werden soll, muss es als erstes aktiviert werden. Das kann mit folgendem SQL-Script geschehen:

Alter Database Inc_Techs1
Set Change_Tracking = ON (AUTO_CLEANUP = OFF)

Beim Aktivieren des Change Tracking werden bereits Datenbankobjekte angelegt, die für das CT erforderlich sind. Diese sind alle für den Datenbank-User nicht sichtbar. In folgender System-View werden alle Datenbanken aufgelistet, die CT aktiviert haben:

Select * from sys.change_tracking_databases

Alternativ kann die Änderungsnachverfolgung auf im SQL Server Management Studio, unter Eigenschaften der Datenbank eingestellt werden.

Nach dem Aktivieren des Change Tracking auf Datenbank-Ebene muss jede Tabelle, die für das CT vorgesehen ist, auch aktiviert werden. Das kann auch über ein SQL-Script erfolgen:

Alter table T_products
Enable Change_Tracking

Auch das ist alternativ im SQL Server Management Studio möglich, in den Eigenschaften zu einer Tabelle.

Mit der Funktion CHANGETABLE kann dann zum einen die Versionsnummer für die einzelnen Zeilen abgefragt werden:

Select
c.SYS_CHANGE_VERSION,
c.SYS_CHANGE_CONTEXT,
p.*
FROM T_products p
CROSS APPLY CHANGETABLE
  ( VERSION T_products,
     (PID),
     (p.PID)
) c

…und außerdem kann mit dieser Funktion auch in Erfahrung gebracht werden, was sich seit einer bestimmten Version geändert hat.

Declare @last_version BIGINT = 4;
 Select
c.*
from CHANGETABLE
(  CHANGES T_products
,  @last_version
) c

Wichtig dabei ist, dass nur die letzte Änderung der Zeile zu sehen ist. D.h. wenn eine Zeile seit der letzten Baseline mehrere Male geändert wurde und dann schließlich gelöscht, ist nur noch ersichtlich, dass diese Zeile gelöscht ist. Sollte also ein absolut vollständiger Verlauf der Zeilenänderungen notwendig sein, ist das ChangeTracking ungeeignet. Auf der anderen Seite ist es eine Technik, die nur wenig mehr Ressourcen benötigt, als das reine Verarbeiten der Daten.

Process-Befehle für das inkrementelle Verarbeiten

Wie bereits weiter oben erwähnt, wird in unserem Standard-Modell die Datenbank immer vollständig prozessiert. Das vollständige Verarbeiten einer AS-Datenbank ist ein sehr stark optimierter Vorgang. Auch bei großen Datenmengen geschieht das meist in einer vertretbaren Zeit. Für Systeme, in denen jedoch eine untertägige Aktualisierung notwendig ist, wird ein inkrementelles Laden besser sein.

Beim inkrementellen Laden ist eine genaue Untersuchung notwendig, was eigentlich geladen werden muss. Verarbeitet werden können auf unterster Ebene Dimension und Partitionen. Es sollte in einer Umgebung mit inkrementellen Laden dann auch auf diesen Ebenen prozessiert werden. Dabei könnte es z.B. möglich sein, nur bestimmte Dimensionen neu zu verarbeiten oder nur neue Faktendaten, je nachdem, was sich geändert hat. Folgende Optionen für das inkrementelle Verarbeiten werden dabei unterstützt:

Inkrementell Verarbeiten

(für Measuregruppen und Partitionen) fügt neue Faktendaten hinzu und verarbeitet relevante Partitionen. Dies entspricht im XMLA-Umfeld der Option ‚ProcessAdd’. Außerdem steht diese Option im XMLA-Umfeld auch für Dimensionen zur Verfügung.

Update Verarbeiten

(für Dimensionen) lädt neue Daten, aktualisiert Dimensionsattribute und flexible Aggregationen, Indizes und Attributbeziehungen. Feste Attributbeziehungen werden nicht geändert. Sollten die zu verarbeitenden Daten eine Änderung einer festen Attributbeziehung erfordern, wird es bei dieser Verarbeitung einen Fehler geben. Hier ist also auch genau darauf zu achten, nur Attributbeziehungen als fest zu deklarieren, die sich wirklich nicht mehr ändern. Diese Option entspricht im XMLA-Umfeld der Option ‚ProcessUpdate’.

Wenn man nun z.B. das Inkrementelle Laden eines multidimensionalen Datenbank verbinden möchte mit dem ChangeTracking der relationalen Datenbank, kann es sinnvoll sein, dass die neue Versionsnummer erst dann als Baseline gespeichert wird, wenn die multidimensionale Datenbank entsprechend verarbeitet ist. Dafür wäre es sehr nützlich, wenn man das Verarbeiten der AS-Datenbank per sql-procedure oder sql-function vornehmen könnte. Ein Weg dafür wäre, eine CLR-Funktion zu schreiben, die einen XMLA-Befehl an die multidimensionale Datenbank senden kann.

Die CLR-Funktion wird im .NET-Umfeld erstellt und in einer DLL gespeichert. Diese wird dann als Assembly in SQL-Server integriert:

Create ASSEMBLY DMM_Tools_R
FROM ‘C:\Test\DMM_Tools_R\DMM_Tools_R\bin\Debug\DMM_Tools_R.dll’
with permission_set = unsafe

Danach kann die sql-Funktion angelegt werden:

Create Function Process
(  @OLAPServer nvarchar(100), @OLAPDatabase nvarchar(100), @ObjectName nvarchar(100)
                 , @ObjectCategory nvarchar(100), @ProcessType nvarchar(50))
returns nvarchar(4000)
as External NAME DMM_Tools_R.GetAS_Info.Process

Jetzt kann diese Funktion in sql-Text verwendet werden, um ein AS-Objekt zu prozessieren. Zum Beispiel:

Select dbo.Process(‘bc-mor-lap\SQL08′, ‘Inc_Techs1′, ‘products’, ‘dimension’, ‘full’)

Der XMLA-Code ist bei dieser Variante vollständig durch die CLR-Funktion gekapselt, sodass hier darauf nicht näher eingegangen werden muss.

ProactiveCaching

Für alle Objekte einer Analysis-Datenbank, welche verarbeitet werden können (also Dimensionen, Cubes oder Partitionen) kann auch das Proaktive Zwischenspeichern eingestellt werden. Sobald das Proaktive Zwischenspeichern aktiviert ist, wird (im Idealfall!) sofort bei einer Änderung der Quelltabelle in der relationalen Datenbank, diese auch in der multidimensionalen Datenbank verarbeitet. Für das Proactive Caching gibt es zwei Modelle, nach denen die Änderungen erfolgen: MOLAP to MOLAP und MOLAP to ROLAP to MOLAP. Unterschied dabei ist, dass bei einer anstehenden Änderung im Fall eins der alte Stand des AS-Objektes solange erhalten bleibt, bis das Verarbeiten abgeschlossen ist. Danach ist der neue Stand des AS-Objektes gültig.

Bei MOLAP to ROLAP to MOLAP wird bei einer anstehende Verarbeitung nach einer bestimmten Zeit das AS-Objekt auf ROLAP (d.h. die Daten werden direkt aus der Quelltabelle auf dem SQL-Server gelesen) umgestellt. So sind noch während der Verarbeitung die aktuellen Daten nutzbar. Nachteil dieses Vorgehens ist jedoch ein merklicher Geschwindigkeitsabfall, da ROLAP-Objekte wesentlich langsamer sind als ihre MOLAP-Gegenstücke.

Timings

Einen großen Einfluss auf das Proaktive Zwischenspeichern hat dabei die Frequenz mit der die Änderungen hintereinander eintreffen können. ProactiveCaching funktioniert so, dass, wenn eine Änderung erfolgt, noch während das System die vorhergehende Änderung prozessiert, wird dieses Prozessieren abgebrochen und das Prozessieren mit den neuen Daten begonnen. Dieses Spiel kann sich solange wiederholen, bis ein Process-Vorgang abgeschlossen werden kann, ohne dass eine neue Änderung ‚dazwischenschießt’. Da das möglicherweise ewig weitergehen könnte, werden 2 Eigenschaften für das proaktive Caching festgelegt: SilenceInterval (Ruheintervall) und SilenceOverrideInterval (Ruhe-Außerkraftsetzungsintervall).

SilenceInterval: Legt das Mindestintervall für die Inaktivität des Objektes fest, bevor das proaktive Zwischenspeichern mit dem Erstellen einer neuen MOLAP-Version des Objektes beginnt. Wird kommt eine Änderung während des Ruheintervalls, wird die Änderung einfach ignoriert.

SilenceOverrideInterval: Legt das Maximumintervall für ein Änderungsmeldung fest, nach der das ProactiveCaching mit der Erstellung einer neuen MOLAP-Version beginnt, unabhängig vom aktuellen Zustand des Objekts.

Sollte das Prozessieren sehr lange dauern, könnte es notwendig sein, auf Performanz zu verzichten, dafür aber sofort die neuesten Daten zur Verfügung zu haben: Ab wann soll das AS-Objekt auf ROLAP umschalten? Diese Einstellung wird über die ‚Latenzzeit’ vorgenommen.

Der vierte Zeitparameter für das proaktive Zwischenspeichern ist das ForceRebuildInterval (Neuerstellungsintervall). Hier wird festgelegt, nach welcher Zeit der Zwischenspeicher neu erstellt wird, egal, ob eine Änderung ansteht oder nicht.

Nicht alle Variationen dieser Zeiträume macht wirklich Sinn, hier sollte also sehr darauf geachtet werden, ob die Einstellungen optimal sind. Analysis Services bieten zu Vereinfachung dieser Einstellung einige Szenarien an, welche direkt gewählt werden können. Diese sind Geplante MOLAP, Automatische MOLAP, MOLAP mit mittlerer Latenzzeit, MOLAP mit geringer Latenzzeit, Echtzeit-HOLAP, Echtzeit-ROLAP. Nach Auswahl eines Szenarios können die Intervalle und Optionen auch noch angepasst werden.