Data Engineering Leitfaden

Dimensional Modeling Guide

Unterschied zwischen einem Data Warehouse, das Analysten lieben, und einem, das sie meiden? Dimensionales Modellieren. Lerne Star Schemas zu bauen, die intuitiv zu queryen sind und blitzschnell laufen.

25 Min. LesezeitFür Analytics & Data EngineersSQL-Beispiele enthalten

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

FrageWenn Antwort ist...Dann ist es...
Kann man SUM/COUNT/AVG darauf anwenden?JaFakt
Würdest du damit GROUP BY oder FILTER machen?JaDimension
Beschreibt es eine Entität?JaDimension
Erfasst es ein Event/eine Transaktion?JaFakt

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.

1

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.

2

Role-Playing Dimensions

Gleiche Dimension, mehrfach genutzt mit anderer Bedeutung. dim_date als order_date, ship_date, delivery_date. Nutze Views oder Aliasse.

3

Degenerate Dimensions

Dimensionsschlüssel liegen in der Fakttabelle ohne eigene Dimension. Bestellnummern, Rechnungs-IDs, Transaktions-IDs. Keine Attribute, die sich lohnen.

4

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.

5

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 Version

SCD 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 berechnet

7. 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.