LearnastraTHE DESIGN COURSE

Make the right trade-off / CHAPTER 41

Normalization versus denormalization

Keep current facts in one place where practical, and explain how any copied display values stay correct.

Intermediate1h of deliberate study10 questions

Builds on SQL versus NoSQL data stores, Functional and non-functional requirements.

By the end, you can
  • Explain update anomalies and read optimization.
  • Distinguish copied current data from historical snapshots.
  • Design reliable derived-view maintenance.

01One fact or many copies?

An author changes her displayed name from Mira to Mira Chen. Suppose that name was copied into every post row. Updating only some posts leaves several different “current” names for the same author.

Normalization reduces that repeated-current-data problem:

  1. Store the author's current name once in an Author record.
  2. Store authorId in each Post record.
  3. When displaying posts, look up the referenced Author record or join it with the posts.

A join combines related records while reading. This layout avoids rewriting every post after a name change, but adds lookup work to reads.

Denormalization deliberately saves a copy or precomputed result to make a particular read cheaper. A feed can copy the display name beside each entry, avoiding repeated author lookups. The design must then explain how those copies are updated, how old they may be and how to repair them. The copied name is not a second independent way to change the author's current name.

02Not all duplication has the same meaning

Use Author(authorId,currentName,version) and Post(postId,authorId,text). Distinguish three meanings that may initially contain the same text:

Layout What does a read do? What should a name change do?
Reference the Author record Load the current name with the post. Change the Author record; reads follow its freshness guarantee.
Copy the name into feed rows Read prepared display fields directly. Update the copies or explicitly allow a delay.
Save a historical name Read the name captured for a past event. Usually preserve that past fact instead of refreshing it.

A materialized view is a saved result of a query, maintained or refreshed so later reads avoid recomputing it. Its existence does not prove it is current.

Plan each copied field:

  1. Identify its source. The Author record accepts current-name changes.
  2. State its meaning. Is the feed displaying the current name, or the name at publication?
  3. Carry a source version. A copied current name can remember which author version it has applied.
  4. Define freshness and rebuilding. Decide how long copies may lag and how to recreate them from source records.
  5. Include deletion. A privacy deletion must cover copied names too; stopping future updates does not erase existing views.

Historical values are separate facts. An order's agreed price must not change when today's catalog price changes.

03Worked example: author names in a feed

Author 17 is the author being renamed. Her current name is Mira at version 4; the edit saves Mira Chen at version 5. She appears in 100,000 feed entries. A background updater safely changes 1,000 entries/s, so one ideal sweep takes 100 seconds, before failures and concurrent work.

  1. Save Author version 5 and pending update work together. A crash must not make the system forget that copied names need refreshing.
  2. A worker sends or reads the author/version change. Delivery can repeat or arrive out of order.
  3. For each current-name feed row, compare versions before changing it. In one conditional row update, replace both name and applied version only if incoming 5 is greater than the version stored in that row. A separate comparison followed by an unguarded write could still let an older worker overwrite a newer name.
  4. A delayed version 4 arrives. The row already remembers 5, so the worker skips the older update instead of restoring Mira.
  5. A new post is inserted during the sweep. The post creator copies the name and version it read, and saves a pending version-check job with the new feed row. That job reads the Author record and conditionally refreshes this row if it copied an older version. This covers inserts missed by the original sweep; merely scanning a snapshot of old rows would not.
  6. Some rows fail. The updater records completed page ranges, such as the last processed post ID, and leaves failed ranges pending. It retries those ranges with the same conditional version update. Repeating a successful update cannot move it backward. Monitor remaining age and rebuild mismatched rows from Author records if necessary.

If every read requires the immediately current name, this delayed sweep cannot meet that promise. A current Author lookup or coordinated publication may be simpler than changing 100,000 copies as though they changed at one instant. One name edit causing many updates is update fanout; count it before choosing the faster read.

Normalization versus denormalization — decision flow

Normalization versus denormalization — decision flowSave the current name and version in the Author record. Feed updaters replace copied names only when the source version is newer. A current-name lookup avoids waiting for the copy sweep; copied display names need an explicit allowed delay. Numbered arrows correspond to the connection key below. All connections are directional.Author 17 recordName changes fromMira to Mira ChenSaved name-changeeventAuthor version 5 maybe delivered againFeed-name workerSkip changes olderthan the appliedversion100,000 feed-namecopiesAssume 1,000 updatesper secondPage rendererRead the name or itsmaintained copy12345Normalization versus denormalization — decision flowSave the current name and version in the Author record. Feed updaters replace copied names only when the source version is newer. A current-name lookup avoids waiting for the copy sweep; copied display names need an explicit allowed delay. Numbered arrows correspond to the connection key below. All connections are directional.Author 17 recordName changes fromMira to Mira ChenSaved name-changeeventAuthor version 5 maybe delivered againFeed-name workerSkip changes olderthan the appliedversion100,000 feed-namecopiesAssume 1,000 updatesper secondPage rendererRead the name or itsmaintained copy12345Normalization versus denormalization — decision flowSave the current name and version in the Author record. Feed updaters replace copied names only when the source version is newer. A current-name lookup avoids waiting for the copy sweep; copied display names need an explicit allowed delay. Numbered arrows correspond to the connection key below. All connections are directional.Author 17 recordName changes fromMira to Mira ChenSaved name-changeeventAuthor version 5 maybe delivered againFeed-name workerSkip changes olderthan the appliedversion100,000 feed-namecopiesAssume 1,000 updatesper secondPage rendererRead the name or itsmaintained copy12345

Follow the numbered arrows

  1. Author 17 record → Saved name-change eventsave work for the committed name change
  2. Saved name-change event → Feed-name workerdeliver the same source version
  3. Feed-name worker → 100,000 feed-name copiesreplace only with a newer author version
  4. 100,000 feed-name copies → Page rendererread the copied display name
  5. Author 17 record → Page rendereroptionally load the current author name
One author record accepts the name change. Feed copies apply newer source versions; a current lookup avoids waiting for their update sweep.
Trace the diagram in words
  1. Save the current name and version in the Author record.
  2. Feed updaters replace copied names only when the source version is newer.
  3. A current-name lookup avoids waiting for the copy sweep; copied display names need an explicit allowed delay.

04Optimize measured reads and preserve meaning

Choose copies only for measured read work:

  • Try an index or bounded join first when it meets the response target with simpler maintenance.
  • Copy only fields the read needs. Duplicating an entire record adds more update and deletion work than copying one display field.
  • Name current and historical data differently. A current-name copy and an order-time snapshot need different update rules.
  • Count the full cost: saved read lookups, copied bytes, updates after one source change, new rows during updates and recovery after failure.
  • Respect retention and privacy. Legitimate history still has a storage and deletion policy.

In the interview, trace one read and one edit. Then stop the updater halfway and insert a new post. Explain which displayed values can be old, how those specific rows are found again and what makes repeated repairs safe.

DRAW. CALCULATE. EXPLAIN.

Maintain titles without rewriting history

20 minutes · guided practice

Product 42 changes its current title at version 9. It appears in 20,000 active listing projections, updated at 500/s, and in historical order lines. A version 8 event arrives late. Specify updates, ideal sweep time and partial-failure repair.

Your self-check
Compare the worked solution
  1. Changing 20,000 active listing copies at 500/s takes 40 seconds ideally, before failures or new listings.
  2. Save product title version 9 and the work needed to update listings. Each listing changes only if 9 is newer than its stored product version.
  3. A late version 8 update is skipped. Save a pending product-version check with each new listing, so a worker can refresh listings inserted after the original sweep’s snapshot.
  4. Preserve historical order-time titles according to their meaning and retention policy; they are not caches of today's title.
  5. Record unfinished listing groups, retry with version checks and rebuild from product records if needed. If immediate current titles are required, reconsider read-time lookup.

The checkboxes record your own assessment. The worked solution gives you a way to check the reasoning.

RETRIEVE BEFORE YOU REVEAL

Keep the important ideas.

Say the answer aloud, then turn the card over.

CARD 01Why normalize a current author name?
  1. Save the current name in one Author record.
  2. Posts reference that author.
  3. Reads look it up or join it, avoiding a name-update sweep across every post.
CARD 02What work does denormalization move?
  1. Copied display fields save read lookups.
  2. Source changes must update many copies.
  3. Keep applied versions, allowed delay and repair rules; measure both saved reads and added maintenance.
CARD 03When should a copied value stay unchanged?

An agreed order price is a past fact, not a cache of today’s price.

  1. Define the field’s meaning.
  2. Preserve legitimate history.
  3. Apply its separate retention and privacy policy.
Practise this topic in the revision deck ↗

CHECK THE REASONING

Can you explain the choice?

Answer every question, then finish for an immediate score and an explanation for each answer. Aim for 80%, then revisit any gaps.

1 / 10Author 17’s name changes. Which normalized record holds the current fact?
2 / 10100,000 copies update at 1,000/s. Ideal sweep duration?
3 / 10Version 5 is applied, then a delayed version 4 event arrives. Correct action?
4 / 10A post is inserted during the name-update sweep. What must the design ensure?
5 / 10Why should an old order keep its agreed unit price?
6 / 10The product now needs immediate current names across all posts. Which option deserves reconsideration?
7 / 10Which measurement fairly evaluates denormalization?
8 / 10What does a materialized view store?
9 / 10Why can deleting only the author source leave a privacy problem?
10 / 10When is a join acceptable?
0 of 10 answered

CLOSE THE LOOP

Explain it without the page.

Summarise the mechanism, one trade-off, and one failure mode. Then mark this chapter complete.