Normalization vs Denormalization
Write-optimized systems vs read-optimized models
OLTP normalizes to avoid write anomalies; BI denormalizes to read fast. The two layers optimize different things — understand the split so you model each correctly.
What you will learn
- Explain why OLTP normalizes and why BI denormalizes
- Recognize 3NF vs star-schema trade-offs
- Decide where each approach belongs in the stack
What is this?
Normalization (3NF and friends) breaks tables into keys and dependency-free attributes to prevent update anomalies and keep writes atomic. Denormalization (stars, wide tables) duplicates attributes on purpose so analytic queries scan fewer joins and read fast. BI models denormalize dims and keep facts at a clear grain as a deliberate trade.
Why do you need it?
- Analytic queries are read-heavy; denormalization cuts join cost.
- Normalized source tables are slow and awkward as direct BI inputs.
- Understanding the split explains why 'the warehouse is not the OLTP db'.
- You'll defend this trade constantly in model reviews.
Mental model
An inventory ledger vs a menu board
Normalized vs denormalized
The ledger records each part's supplier once (normalized — no contradictions). The kitchen menu writes the dish's price onto every table's board (denormalized — repeat but fast). One keeps truth; the other serves diners quickly. BI is the menu; the ledger stays upstream.
How it works
- Normalization splits attributes across tables joined by keys; uniqueness enforced.
- Denormalization repeats attributes (e.g., category on every product row) to avoid joins.
- Stars are semi-denormalized: dims fully denormalized, facts kept clean at grain.
- Kimball-style dims are flat attribute bags; snowflakes re-normalize dims a bit (rarely worth it).
- The layer decides: OLTP normalizes, warehouses conform, reporting stars denormalize.
OLTP → warehouse → denormalized BI.
Examples
The same business, two shapes
-- Normalized (OLTP):product (prod_id PK, name)category (cat_id PK, name)product_category (prod_id, cat_id) -- FK pairs -- Denormalized (BI dim):dim_product (prod_id PK, product_name, category_name, subcategory_name, brand, margin_bucket) Trade: some duplication (category repeated) buys zero-joinfiltering and one-view dimension descriptions.The dim repeats category name instead of joining category tables — a deliberate read-speed trade the warehouse accepts.
In production
- A sales model keeps dim_product flat, so 'filter by category' scans one column.
- An ops model joins margins into the order fact directly, skipping margin-join at query time.
- A source ERP stays strictly 3NF; the BI layer denormalizes only downstream of it.
Best practices
- Return by layer identity: normalize only where writes dominate (OLTP).
- Denormalize dims; keep facts clean and grain-precise.
- Document repeated attributes so consumers know why duplication exists.
- Test read performance before deeply denormalizing a wholesale.
Common mistakes
- Shipping normalized ERP tables straight to dashboards (join hell).
- Fully denormalizing facts into 'one giant table' everyone fears.
- Snowflake-ing dims to 'be clean', losing the read advantage.
- Vague explanations for duplication — the model becomes a guessing game.
Debugging tips
- Slow cross-filtering → likely missing denormalization or a snowflake dim.
- Write anomalies (same product in two categories) → normalization intent violated upstream.
- Update lags → denormalized copies must be rebuilt on source change.
Interview checkpoint
Quick quiz
Normalization primarily optimizes which kind of workload?
Denormalization is acceptable in BI dimensions to cut query-time joins.