1. Was ist dimensionales Modellieren?
Dimensionales Modellieren ist eine Technik zum Design von Data Warehouses, die Query-Simplicity und Performance vor Speichereffizienz stellt. Von Ralph Kimball entwickelt, bleibt es Standard für Analytics, weil es Daten so modelliert, wie Business-User denken.
Warum nicht einfach 3NF?
Third Normal Form (3NF) ist top für OLTP: minimale Redundanz, keine Update-Anomalien. Für Analytics aber schlecht: 15+ Joins pro Query, Performance leidet und Analysten brauchen ein Schema-PhD.
Kernprinzip: Trenne das "Was passierte" vom "Kontext"
Fakttabellen
Speichern Events und Messungen: Bestellungen, Klicks, Zahlungen. Enthalten Kennzahlen, die aggregiert werden können (SUM, COUNT, AVG).
Dimensionstabellen
Speichern beschreibenden Kontext: wer (Kunden), was (Produkte), wann (Daten), wo (Standorte). Ermöglichen Filtern und Gruppieren.
Kimball-Philosophie
"Das Data Warehouse ist nur so gut wie die BI, die es ermöglicht." Dimensionales Modellieren ist für Menschen gebaut, nicht für Maschinen. Wenn Analysten ohne Hilfe keine Queries schreiben können, ist das Modell gescheitert.
2. Fakten vs. Dimensionen
Die Grundbausteine des dimensionalen Modellierens. Wenn das sitzt, passt der Rest.
Fakttabellen
- Speichern Events/Transaktionen
- Enthalten numerische Kennzahlen (Betrag, Anzahl, Dauer)
- Haben Fremdschlüssel zu Dimensionen
- Sehr hoch und schmal (viele Zeilen, wenige Spalten)
- Korn = eine Zeile pro Event
Beispiele:
fct_orders, fct_page_views, fct_payments
Dimensionstabellen
- Speichern beschreibende Attribute
- Enthalten Textfelder zum Filtern/Gruppieren
- Haben einen Surrogate Key als Primärschlüssel
- Kurz und breit (wenige Zeilen, viele Spalten)
- Korn = eine Zeile pro Entität
Beispiele:
dim_customers, dim_products, dim_date
| Frage | Wenn Antwort ist... | Dann ist es... |
|---|---|---|
| Kann man SUM/COUNT/AVG darauf anwenden? | Ja | Fakt |
| Würdest du damit GROUP BY oder FILTER machen? | Ja | Dimension |
| Beschreibt es eine Entität? | Ja | Dimension |
| Erfasst es ein Event/eine Transaktion? | Ja | Fakt |
Beispiel: E-Commerce Bestellung
-- Faktentabelle: eine Zeile pro Order-Position
CREATE TABLE fct_order_lines (
order_line_sk BIGINT PRIMARY KEY, -- Surrogate Key
order_id VARCHAR(50), -- Natural Key (degenerate dimension)
customer_sk BIGINT REFERENCES dim_customers,
product_sk BIGINT REFERENCES dim_products,
date_sk INT REFERENCES dim_date,
-- Kennzahlen (aggregierbar)
quantity INT,
unit_price DECIMAL(10,2),
discount_amount DECIMAL(10,2),
line_total DECIMAL(10,2)
);
-- Dimensionstabelle: eine Zeile pro Kunde
CREATE TABLE dim_customers (
customer_sk BIGINT PRIMARY KEY, -- Surrogate Key
customer_id VARCHAR(50), -- Natural Key
customer_name VARCHAR(255),
email VARCHAR(255),
segment VARCHAR(50), -- 'Enterprise', 'SMB', 'Consumer'
acquisition_channel VARCHAR(50),
created_at TIMESTAMP
);3. Star Schema Design
Ein Star Schema platziert eine Fakttabelle ins Zentrum, umgeben von Dimensionstabellen. Name kommt von der Form: Fakt in der Mitte, Dimensionen wie Sternstrahlen außen.
Star Schema Struktur
dim_date
dim_customer
fct_orders
dim_product
dim_store
Fakttabelle in der Mitte, Dimensionen außen – einfache Joins, intuitive Queries
Star vs. Snowflake Schema
Star Schema (bevorzugt)
- • Dimensionen sind denormalisiert
- • Weniger Joins = schnellere Queries
- • Leichter zu verstehen und zu queryen
- • Leichte Redundanz (für Analytics ok)
Snowflake Schema
- • Dimensionen sind normalisiert
- • Mehr Joins = langsamere Queries
- • Ohne Doku schwer zu queryen
- • Spart Speicher (kaum relevant)
Pro Tipp
Wann snowflaken?
Snowflake nur, wenn Dimensionen echte Hierarchien haben UND Analysten regelmäßig auf unterschiedlichen Ebenen separat queryen (z. B. Produkt → Kategorie → Abteilung). Sonst alles in die Dimension denormalisieren.
4. Dimensionstypen
Nicht alle Dimensionen sind gleich. Diese Muster helfen dir, von Anfang an korrekt zu modellieren.
Conformed Dimensions
Werden über mehrere Fakttabellen geteilt. dim_date, dim_customer, genutzt von fct_orders, fct_page_views, fct_support_tickets. Schlüssel für konsistente Berichte.
Role-Playing Dimensions
Gleiche Dimension, mehrfach genutzt mit anderer Bedeutung. dim_date als order_date, ship_date, delivery_date. Nutze Views oder Aliasse.
Degenerate Dimensions
Dimensionsschlüssel liegen in der Fakttabelle ohne eigene Dimension. Bestellnummern, Rechnungs-IDs, Transaktions-IDs. Keine Attribute, die sich lohnen.
Junk Dimensions
Bündelt diverse Flags niedriger Kardinalität in einer Dimension. Statt 5 Boolean-Spalten in der Fakttabelle: dim_order_flags mit allen Kombinationen.
Date Dimension
Die wichtigste Dimension. Vorgefüllte Attribute: day_of_week, is_weekend, fiscal_quarter, holiday_flag. Immer integer Surrogate Keys nutzen (Format YYYYMMDD).
Beispiel: Date Dimension
CREATE TABLE dim_date (
date_sk INT PRIMARY KEY, -- YYYYMMDD Format
date_actual DATE NOT NULL,
day_of_week VARCHAR(10), -- 'Monday', 'Tuesday', ...
day_of_week_num INT, -- 1-7
day_of_month INT,
day_of_year INT,
week_of_year INT,
month_num INT,
month_name VARCHAR(10),
quarter_num INT,
quarter_name VARCHAR(10), -- 'Q1', 'Q2', ...
year_num INT,
fiscal_year INT,
fiscal_quarter INT,
is_weekend BOOLEAN,
is_holiday BOOLEAN,
holiday_name VARCHAR(50)
);
-- Nutzung: einfach nach beliebigem Datumsattribut filtern/gruppieren
SELECT
d.month_name,
d.year_num,
SUM(f.order_total) as revenue
FROM fct_orders f
JOIN dim_date d ON f.order_date_sk = d.date_sk
WHERE d.is_weekend = FALSE
GROUP BY d.month_name, d.year_num;5. Slowly Changing Dimensions (SCD)
Dimensionattribute ändern sich über die Zeit. Kunde zieht um, Produkt wird neu kategorisiert, Mitarbeitende wechseln Abteilungen. Wie du das handhabst, entscheidet über historische Genauigkeit.
Typ 0: Fix
Ändert sich nie. Ursprungswert bleibt für immer. Nutze für Attribute, die unveränderlich sein sollen (erste Registrierung, Geburtsdatum).
Beispiel: Ursprünglicher Akquisekanal des Kunden bleibt, auch wenn später ein anderer Kanal kommt.
Typ 1: Overwrite
Alter Wert wird überschrieben. Keine Historie. Nutze für Korrekturen und Attribute, bei denen Historie egal ist.
Trade-off: Einfach, aber du verlierst die Frage "Wie war das Segment beim damaligen Kauf?"
Typ 2: Neue Zeile (am häufigsten)
Neue Dimensionszeile mit neuem Surrogate Key. Tracking über effective_date, expiry_date, is_current Flag. Volle Historie bleibt erhalten.
Bestens geeignet für: Alle Attribute, bei denen Historie zählt. Segmentwechsel, Adressänderung, Pricing-Tier.
Typ 3: Neue Spalte
Spalten für current_value und previous_value. Begrenzte Historie (meist nur ein vorheriger Wert).
Selten: Nur sinnvoll für genau "vorher/nachher" Vergleiche. Typ 2 ist fast immer besser.
Beispiel: SCD Typ 2
-- SCD Typ 2: Kunde wechselt Segment von 'SMB' zu 'Enterprise'
-- VORHER: 1 Zeile
customer_sk | customer_id | segment | effective_date | expiry_date | is_current
1 | C001 | SMB | 2023-01-01 | 9999-12-31 | TRUE
-- NACHHER: 2 Zeilen (alte Zeile abgelaufen, neue hinzugefügt)
customer_sk | customer_id | segment | effective_date | expiry_date | is_current
1 | C001 | SMB | 2023-01-01 | 2024-06-15 | FALSE
2 | C001 | Enterprise | 2024-06-15 | 9999-12-31 | TRUE
-- Historische Abfrage: Welches Segment beim Order?
SELECT
o.order_id,
c.segment as segment_at_order_time
FROM fct_orders o
JOIN dim_customers c ON o.customer_sk = c.customer_sk
-- customer_sk in der Fakttabelle zeigt auf die passende historische VersionSCD Typ 2 Stolperstein
Bei Typ 2 musst du beim Load entscheiden, welchen Surrogate Key du der Fakttabelle gibst. Meist willst du die Version, die zum Event-Zeitpunkt "current" war. Das braucht einen Point-in-Time Lookup im ETL.
6. Faktentabellen-Typen
Unterschiedliche Geschäftsprozesse brauchen unterschiedliche Faktentabellen. Wähle den Typ passend zur Natur deiner Events.
Transaction Facts
Eine Zeile pro Event auf niedrigstem Korn. Am häufigsten. Bestellungen, Klicks, Zahlungen, Logins.
Korn: Eine Zeile pro Order-Position
Periodic Snapshot Facts
Eine Zeile pro Zeitraum. Erfasst den Zustand in Intervallen. Kontostände, Lagerbestände, Pipeline-Snapshots.
Korn: Eine Zeile pro Account pro Tag
Accumulating Snapshot Facts
Eine Zeile pro Prozessinstanz, die mit Meilensteinen aktualisiert wird. Order-Fulfillment, Kreditanträge, Support-Tickets.
Korn: Eine Zeile pro Bestellung (über Lifecycle aktualisiert)
Factless Facts
Zeichnen Events ohne Kennzahlen auf—nur Fremdschlüssel. Anwesenheit von Schülern, Promotion-Abdeckung für Produkte.
Nutzen: Wer war anwesend? Welche Produkte waren in Promotion?
Beispiel: Accumulating Snapshot (Order Fulfillment)
CREATE TABLE fct_order_fulfillment (
order_sk BIGINT PRIMARY KEY,
order_id VARCHAR(50),
customer_sk BIGINT,
-- Mehrere Datums-FKs (Meilensteine)
order_date_sk INT,
payment_date_sk INT,
ship_date_sk INT,
delivery_date_sk INT,
-- Lag-Kennzahlen (berechnet)
days_to_payment INT,
days_to_ship INT,
days_to_delivery INT,
-- Kennzahlen
order_total DECIMAL(10,2),
current_status VARCHAR(50)
);
-- Zeile wird aktualisiert, wenn Bestellung fortschreitet
-- Initial: nur order_date_sk
-- Nach Zahlung: payment_date_sk gefüllt, days_to_payment berechnet
-- Nach Versand: ship_date_sk gefüllt, days_to_ship berechnet
-- Nach Lieferung: delivery_date_sk gefüllt, days_to_delivery berechnet7. Best Practices Checkliste
Korn zuerst definieren
Bevor du eine Fakttabelle designst, schreibe das Korn explizit auf: "Eine Zeile pro Order-Position" oder "Eine Zeile pro Kunde pro Tag". Keine gemischten Körner.
Surrogate Keys nutzen
Integer Surrogate Keys in allen Dimensionstabellen. Natural Keys als Attribute speichern. Funktioniert sauber mit SCD Typ 2 und verbessert Joins.
Conformed Dimensions bauen
dim_date und dim_customer sollten über alle Fakttabellen geteilt werden. Gleiche Keys, gleiche Attribute. Ermöglicht Prozess-übergreifende Analysen.
Dimensionen denormalisieren
Bevorzuge Star gegenüber Snowflake. Kategorie, Abteilung, Region direkt in die Dimension packen. Speicher ist günstig, Joins sind teuer.
Date Dimension hinzufügen
Nie auf rohe Dates joinen. Erstelle dim_date mit vorberechneten Attributen. Integer Keys (YYYYMMDD) für Partition Pruning.
Nulls mit Default-Zeilen abfangen
Erstelle "Unknown" oder "Not Applicable" Zeilen in Dimensionen (SK = -1). Keine Null-FKs in Fakttabellen.
Korn dokumentieren
Jede Fakttabelle braucht dokumentiertes Korn. Verhindert Double-Counting und hilft Analysten bei korrekten Queries.
Wichtige Attribute mit SCD Typ 2
Kundensegment, Produktkategorie, Abteilung—alles, was sich ändert und Analyse beeinflusst, sollte Typ 2 sein.
Pro Tipp
Der "Analysten-Test"
Lass nach dem Design eine Analystin fünf typische Queries ohne Doku schreiben. Wenn es unter 5 Minuten pro Query klappt, ist dein Modell gut. Wenn Fragen auftauchen oder Fehler passieren, vereinfache das Design.
8. Häufige Fragen
Was ist der Unterschied zwischen Fakt- und Dimensionstabelle?
Fakttabellen speichern messbare Geschäftsvorfälle (Transaktionen, Klicks, Bestellungen) mit numerischen Kennzahlen und Fremdschlüsseln. Dimensionstabellen speichern beschreibende Attribute (Kundennamen, Produktkategorien, Daten) und liefern Kontext. Fakten beantworten "wie viel", Dimensionen "wer, was, wann, wo, warum".
Was ist ein Star Schema vs. Snowflake Schema?
Ein Star Schema hat denormalisierte Dimensionstabellen direkt an einer zentralen Fakttabelle, Form eines Sterns. Snowflake normalisiert Dimensionen in Unterdimensionen (Produkt → Kategorie → Abteilung). Star wird bevorzugt, weil einfacher und schneller.
Was sind Slowly Changing Dimensions (SCD)?
SCD handhaben Attributänderungen über Zeit. Typ 1 überschreibt, keine Historie. Typ 2 legt neue Zeile mit Gültigkeitsdaten an, volle Historie. Typ 3 fügt Spalten für vorherige Werte hinzu, begrenzte Historie. Typ 2 ist Standard für historische Genauigkeit.
Surrogate Keys oder Natural Keys?
Nutze Surrogate Keys (auto-generierte Integer) als Primärschlüssel in Dimensionen. Natural Keys (z. B. customer_id) als Attribute speichern. Surrogate Keys sind stabil, performant und funktionieren mit SCD Typ 2. Natural Keys können sich ändern und Joins brechen.
Visualisiere dein dimensionales Modell
Erstelle klare Star-Schema-Diagramme mit Fakten, Dimensionen und Beziehungen. Dokumentiere dein Datenmodell, damit Analysten ohne Rückfragen queryen können.