Im Rahmen der Modellierung von Data-Warehouse-Systemen haben sich in der Vergangenheit zwei Modelle
etabliert: 3. Normalform (3NF) oder
das Sternschema. Beide Ansätze haben Nachteile, die durch eine Modellierung
nach Data-Vault beseitigt werden. Das Sternschema z. B. nimmt für die gesteigerte Performance eine denormalisierte
Speicherung der Daten in Kauf. Durch diese Denormalisierung können
schnell Probleme mit der Datenintegrität auftreten. 3NF-Modelle dagegen leiden in der Regel unter einer schlechten
Lesegeschwindigkeit, da die Daten zunächst per JOIN
zusammengesucht werden müssen. Beide Probleme können mittels
Data-Vaults gelöst werden.
Basisbausteine
Im Rahmen der Modellierung von Data-Vaults existieren 3 Basisbausteine, mit denen (fast) das komplette Model abgebildet werden kann. Diese lauten wie folgt:
Hubs
Mittels sog. Hubs werden Business-Entitäten abgebildet. Die Tabellenstruktur für einen Hub muss daher zwingend einen Business-Schlüssel beinhalten, der diese Entität eindeutig identifiziert. Im einfachsten Fall könnte dies wie folgt aussehen:
+----------------+
| <business_id> |
+----------------+
| business value |
| ... |
+----------------+
Hubs sollten nach der Business-Entität benannt werden, die sie abbilden. Es ist nicht zwingend erforderlich, dass Hubs
mit einem bestimmten Präfix anfangen. Sofern ein Team Konventionen für die Benennung von Hubs einführen möchte, hat sich
in der Praxis wahlweise „H_” oder „HUB_” etabliert, wie z. B. „HUB_PERSON”. Sowohl bei Hubs als auch bei allen
folgenden Tabellen ist es optional möglich einen technischen Schlüssel hinzuzufügen und diesen ebenfalls
als PRIMARY KEY
zu markieren.
Links
Mittels sog. Links werden Hubs miteinander verbunden. Die Tabellenstruktur für einen Link muss daher immer
mindestens zwei Identifier beinhalten - einen für jede Verbindung. Alle Identifier sollten als FOREIGN KEY
den
jeweiligen Hub referenzieren. Im einfachsten Fall könnte dies wie folgt aussehen:
+----------------+-------------+
| <business_id> | <other_id> |
+----------------+-------------+
| business value | other value |
| ... | ... |
+----------------+-------------+
Links sollten nach der Business-Relation benannt werden. Zum Beispiel könnte ein Hub für Personen (HUB_PERSON) und ein Hub für Firmen (HUB_COMPANY) mehrmals miteinander verbunden sein, um auszudrücken, dass eine Person sowohl Kunde bei einer Firma sein kann, als auch als Angestellter. Beide Verbindungen werden als separate Links im Data-Vault abgebildet. Sofern eine Konvention eingehalten werden soll/muss, hat sich in der Praxis „L_” oder „LINK_” etabliert, wie z. B. „LINK_EMPLOYMENT” oder „LINK_CUSTOMER”.
Satellites
Weder Hubs noch Links beinhalten Business-Daten. Für diese Aufgabe existieren Satellites, die sowohl mit Hubs als auch Links verbunden werden können. Neben der Referenz auf entweder Hub oder Link können in einem Satellite beliebig weitere Spalten hinzugefügt werden, um beliebige Daten zu erfassen. Ein einfacher Satellite könnte wie folgt aussehen:
+----------------+-------------+
| <business_id> | <some_data> |
+----------------+-------------+
| business value | entry |
| ... | ... |
+----------------+-------------+
Jeder Hub oder Link kann mehrere Satellites haben, daher empfiehlt es sich, Satellites nicht zu groß werden zu lassen, um den Überblick nicht zu verlieren. In der Praxis hat sich „S_” oder „SAT_” als Namenskonvention etabliert, wie z.B. „SAT_PERSON”.
Praktisches Beispiel
Im folgenden Beispiel werden wir nach und nach ein Data-Vault-Schema aufbauen und dazu Postgres als Datenbank benutzen. Alle Tabellen werden mit einem technischen Schlüssel modelliert. Als ersten Schritt werden die Hubs erstellt:
CREATE TABLE hub_person
(
hub_person_id SERIAL PRIMARY KEY,
id_number TEXT
);
Die Spalte hub_person_id
wird per SERIAL
-Type automatisch mit einer fortlaufenden Nummer befüllt und entspricht dem
technischen Schlüssel, der weiter oben besprochen wurde. Die Spalte id_number
beinhaltet die Ausweisnummer einer
Person und ist in unserem Beispiel die Business-Sicht auf eine Person.
CREATE TABLE hub_company
(
hub_company_id SERIAL PRIMARY KEY,
tax_number TEXT
);
Wie man am Hub für Firmen (HUB_COMPANY) gut sehen kann, sehen Hubs fast immer gleich aus. Es ändern sich in der Regel
immer die Namen der Spalten, aber seltener die Struktur. Die Spalte hub_company_id
dient wieder als technischer
Schlüssel und tax_number
ist der Business-Schlüssel.
Als nächstes erstellen wir zwei Relationen zwischen diesen Hubs:
CREATE TABLE link_employment
(
link_employment_id SERIAL PRIMARY KEY,
hub_person_id BIGINT REFERENCES hub_person (hub_person_id),
hub_company_id BIGINT REFERENCES hub_company (hub_company_id)
);
CREATE TABLE link_customer
(
link_customer_id SERIAL PRIMARY KEY,
hub_person_id BIGINT REFERENCES hub_person (hub_person_id),
hub_company_id BIGINT REFERENCES hub_company (hub_company_id)
);
Die Referenzen in diesen Links verweisen auf die technischen Schlüssel. Falls für einen Link kein technischer Schlüssel
erzeugt werden soll, kann auch ein kombinierter PRIMARY KEY
verwendet werden. Bei allen Referenzen auf diesen Link
müssen dann allerdings auch immer zwei (oder mehrere) Spalten referenziert werden.
-- Beispiel mit kombinierten Primary Key
CREATE TABLE link_customer
(
hub_person_id BIGINT REFERENCES hub_person (hub_person_id),
hub_company_id BIGINT REFERENCES hub_company (hub_company_id),
CONSTRAINT link_customer_pk PRIMARY KEY (hub_person_id, hub_company_id)
);
Zum Abschluss legen wir noch Satellites an, um Daten zu diesen Hubs und Links abzuspeichern:
CREATE TABLE sat_employment_contract
(
sat_employment_contract_id SERIAL PRIMARY KEY,
link_employment_id BIGINT REFERENCES link_employment (link_employment_id),
entry_date DATE,
exit_date DATE
);
CREATE TABLE sat_person_name
(
sat_person_name_id SERIAL PRIMARY KEY,
hub_person_id BIGINT REFERENCES hub_person (hub_person_id),
first_name TEXT,
last_name TEXT
);
CREATE TABLE sat_company
(
sat_company_id SERIAL PRIMARY KEY,
hub_company_id BIGINT REFERENCES hub_company (hub_company_id),
name TEXT,
stock MONEY
);
Es mag merkwürdig erscheinen, dass mehrere Einträge pro z. B. hub_company_id
in sat_company
erstellt werden können,
aber in einem Data-Vault können und sollen alle Daten zu allen Zeiten abgelegt werden. Der technische Schlüssel kann
als fortlaufende Versionsnummer interpretiert werden und sorgt dafür, dass bei Änderung an den Daten kein UPDATE
,
sondern ein INSERT
ausgeführt wird. Beim Auslesen der Daten muss dann derjenige Eintrag gewählt werden, dessen
Referenz auf den jeweiligen Hub übereinstimmt und deren technischer Schlüssel den höchsten Wert hat. Ein
einfaches SELECT
-Statement könnte wie folgt aussehen:
SELECT hc.tax_number, sc.name, sc.stock
FROM hub_company hc
INNER JOIN sat_company sc
USING (hub_company_id)
ORDER BY sc.sat_company_id DESC LIMIT 1
Sofern diese Form der Historisierung/Versionierung nicht erwünscht ist, kann natürlich weiterhin auf UPDATE
-Statements
zurückgegriffen werden. In diesem Fall sollte die Referenz zwischen Satellite und Hub/Link als UNIQUE
markiert werden,
um sicherzuerstellen, dass keine unnötigen Einträge erstellt werden.
Die Einträge in Hubs, Links und Satellites müssen in eben dieser Reihenfolge geschrieben werden, um sicherzustellen, dass die referentielle Integrität gewährleistet ist. Also zunächst neue Einträge in den Hubs erstellen, dann die Relationen mittels der Links aufbauen und abschließend die Satellites mit Daten befüllen.
Fortgeschrittene Themen
Referenztabellen
Um eindeutige Werte, wie z. B. der Name einer Währung, nicht mehrfach in Satellites zu speichern, können Referenztabellen verwendet werden. Diese sind ähnlich aufgebaut wie Satellites, da aber in der Regel kein zugehöriger Hub existiert, entfällt die Referenz auf diesen. Eine Referenztabelle für Währungen könnte z. B. wie folgt aussehen:
+-------------+-------------+
| currency_id | name |
+-------------+-------------+
| 123 | EUR |
| ... | ... |
+-------------+-------------+
Alle Satellites sollten dann nicht mehr den Wert EUR
beinhalten, sondern nur noch eine Referenz auf die Währung mit
der currency_id
123
, über die dann der ursprüngliche Wert ermittelt werden kann. Die Referenz von Satellite zu
Referenztabelle sollte als FOREIGN KEY
abgebildet werden, um sicherzustellen, dass keine unbekannten Werte gespeichert
werden.
Hierarchien
Um Hierarchien in Data-Vault abzubilden ist mindestens ein Hub und ein Link notwendig. Um z. B. eine Hierarchie unter Mitarbeitern im HUB_EMPLOYEE auszudrücken, wird ein Link LINK_EMPLOYEE_HIERARCHY erstellt, der zwei mal HUB_EMPLOYEE referenziert.
CREATE TABLE link_employee_hierarchy
(
boss BIGINT REFERENCES hub_employee (hub_employee_id),
employee BIGINT REFERENCES hub_employee (hub_employee_id),
CONSTRAINT link_employee_hierarchy_pk PRIMARY KEY (parent, child)
);
Audit
In den bisher gezeigten Tabellenstrukturen fehlt bislang Informationen, woher die Daten stammen, wann sie geschrieben
und insbesondere auch von wem bzw. von welchem Prozess. Diese Art von Auditinformationen mag für eine einzelne Anwendung
ein Overkill sein, für ein Data-Warehouse sind diese Informationen aber essentiell. Denkbar wäre z. B. eine weitere
Spalte pro Hub/Link/Satellite, die auf eine Audit
-Tabelle verweist. In dieser Tabelle befinden sich dann Informationen
für jeden einzelnen Ladevorgang.
Fazit
Die Modellierung nach Data-Vault ist flexibel, da zukünftige Änderung vorgenommen werden können, ohne dass bestehende Strukturen geändert werden müssen. Sollen neue Business-Entitäten hinzugefügt werden, wird ein neuer Hub angelegt. Wurde eine neue Relation zwischen zwei Hubs identifiziert, wird ein neuer Link angelegt und sofern neue Daten erfasst werden sollen, wird ein neuer Satellite angelegt.
Gleichzeitig bietet Data-Vault eine sehr hohe Schreibperformance, da parallel in alle Hubs, dann parallel in alle Links und abschließend parallel in alle Satellites geschrieben werden kann. Data-Vaults skalieren daher beliebig mit der vorhandenen Hardware bzw. den vorhandenen Datenvolumen.
Die Lesegeschwindigkeit ist allerdings ohne weitere Arbeiten schlecht. Wie am obigen SELECT
-Beispiel zu sehen ist,
muss für eine Abfrage in der Regel mindestens ein JOIN
ausgeführt werden. Durch eine Voraggregation der Daten, z. B.
mittels einer MATERIALIZED VIEW
oder einem
gesonderten Data-Mart, bringt die Performance aber wieder auf ein Maß, dass
sich mit dem Sternschema messen kann.
Im Ergebnis haben wir so ein Datenbankschema, das wir beliebig um weitere Tabellen/Spalten erweitern können, sehr schnell Schreiben und mit wenig Aufwand auch sehr schnell wieder Lesen können.
Weiteres zum Thema finden sie im Buch von Daniel Linstedt.