Chapter 77·Intermediate·9 min read
Normalization vs Denormalization: Shaping Data Well
A deep, plain-English guide to normalization — why duplicated data causes anomalies, what the normal forms actually ask of you, and the deliberate, measured cases where denormalizing for read speed is the right call.
July 6, 2026
We've seen how data behaves — indexed, joined, transacted. Now the upstream question that determines how much pain all of that causes: how should the data be shaped? Normalization is the discipline of organizing tables so each fact lives in exactly one place. Done well, whole categories of bug simply cannot occur.
The disease: duplicated facts
Imagine cramming everything into one wide orders table, repeating the customer's details on every row:
| order_id | customer_email | customer_city | total |
|---|---|---|---|
| 501 | ada@example.com | London | 42.00 |
| 502 | ada@example.com | London | 18.50 |
| 503 | ada@example.com | Paris | 99.00 |
Ada's city is stored three times — and row 503 disagrees. Which is true? The schema can't say. This duplication breeds three classic anomalies:
- Update anomaly — Ada moves cities; you must change every order row, and missing one leaves the data contradicting itself.
- Insertion anomaly — you can't record a customer until they place an order, because their details only exist as columns of
orders. - Deletion anomaly — delete Ada's last order and you erase the only record that she existed at all.
The cure: normal forms
The normal forms are a progression of rules that squeeze out redundancy. You don't need to memorize the theory; you need the intent behind the first three, which cover the overwhelming majority of designs.
First Normal Form (1NF) — each column holds a single, atomic value; no lists crammed into one field, no repeating groups of columns. One value per cell.
Second Normal Form (2NF) — every non-key column depends on the whole primary key, not just part of it. (Relevant when the key is composite.)
Third Normal Form (3NF) — non-key columns depend on the key and nothing but the key. customer_city doesn't belong in orders because it depends on the customer, not the order.
Applying this, the wide table splits cleanly into two, linked by a foreign key:
Now Ada's city lives in a single customers row. Change it once and every order reflects it instantly, because orders don't store the city — they point at the customer who has it. The anomalies are gone by construction.
The deliberate exception: denormalization
Normalization's cost is joins. Reassembling data spread across many tables takes work, and on a very hot read path with huge tables, those joins can become the bottleneck. Denormalization is the conscious decision to reintroduce some duplication to avoid that work.
The classic example: storing an order_count on each customer rather than counting order rows every time it's displayed. The read becomes a single-column fetch instead of an aggregation over thousands of rows.
But you've bought that speed with a liability: the copied value must be kept in sync. Every event that changes the underlying data now has to update the duplicate too — and if any path forgets, you're back to contradictory data, the exact disease normalization cured.
The discipline: which way to lean
The rule that keeps schemas healthy: normalize by default, denormalize by evidence. A normalized schema is correct without effort — it's the safe starting point, and modern databases join efficiently far more often than beginners fear. Denormalize only when you have a measured performance problem that a well-placed index or query fix can't solve, and only with clear ownership of the now-duplicated data. Reaching for denormalization first is premature optimization that trades a real guarantee for an imagined gain.
Recap
- Normalization stores each fact in exactly one place, eliminating update, insertion, and deletion anomalies at the source.
- Those anomalies all stem from one cause: duplicated data the schema can't keep consistent.
- 1NF → 2NF → 3NF progressively remove redundancy; 3NF covers most real designs — every non-key column depends on the key and nothing else.
- Denormalization deliberately re-adds duplication to skip expensive joins on hot reads — trading read speed for the burden of syncing copies.
- The discipline: normalize first, denormalize only with measured evidence and clear ownership of the copies.
We've assumed a relational database throughout. When is that the right choice — and when isn't it? Continue to SQL vs NoSQL: When Each Wins.