Pre-joined / merged column — a column copied from the parent table into the child to kill a join.
Pre-computed / derived column — stores an aggregate that would otherwise be recomputed.
Inline repeating / array column — a list stored in-row instead of via a junction table.
Materialized view — a cached result of an expensive query, refreshed on a schedule.
Recall Solution L1.2
Makes reads cheaper (fewer/no joins) and writes more expensive (you must keep the copies in sync). You are moving cost from the read path to the write path, not deleting it. The figure below shows this schema move concretely.
Right: CjoinCsync=23=1.5.
Since 500>1.5, the inequality holds → denormalize. On the decision-boundary map this workload sits far to the right of the diagonal.
Cross-check with net saving Δ=frCjoin−fwCsync=5000⋅2−10⋅3=10000−30=9970 units/day saved. Strongly positive.
Recall Solution L2.2
Set Δ=frCjoin−fwCsync=0 and solve for fr:
fr=CjoinfwCsync=24000⋅3=6000 reads/day.
So you need at least 6000 reads/day to justify it. Below that, staying normalized wins. This fr is exactly the point where the workload lands on the diagonal boundary — and, from the tie-case rule above, break-even alone is not a reason to denormalize; you'd want to be clearly past it.
(a) Normalized read cost = views × N = 2000×1,000,000=2,000,000,000 row-scans/day (2 billion).
(b) Denormalized: each read touches 1 stored value (2000 reads → 2000 touches) and each write touches 1 row (500 writes → 500 touches). Total = 2000+500=2500 row-touches/day.
(c) Factor = 25002,000,000,000=800,000. Denormalizing cuts row work by 800,000×. This is why aggregate counts are the textbook denormalization case.
Recall Solution L3.2
(a) The diagonal boundary crosses at fr/fw=2.
(b) Csync/Cjoin=4/2=2. ✅ They match exactly — the break-even ratio is the cost ratio, which is precisely what the boxed rule says. Right of the line, denormalizing wins; left of it, stay normalized. And on the line (the blue dot) is the tie: Δ=0, so you would not denormalize there.
Trigger (i) fits best. It runs inside the same transaction as the item change, so total_amount is always consistent atomically — no window where the order shows a wrong total. The transactional flow is drawn below.
App logic (ii) works but is fragile: if any code path (a script, an admin tool, a bulk import) writes order_items without going through that code, the total drifts. The invariant lives outside the database.
Scheduled refresh (iii) is wrong for "exact instantly": it leaves a staleness window between refreshes. That's fine for a dashboard, not for a checkout total. Materialized-view refresh trades freshness for cheaper writes — the opposite of what this requirement wants.
Recall Solution L4.2
(a) Left =fr/fw=10000/200=50. Right =Csync/Cjoin=6/5=1.2. Since 50>1.2 → denormalize. Net Δ=10000⋅5−200⋅6=50000−1200=48800 units/day saved.
(b) Add users.follower_count; guard it with a trigger on follows that does +1 on insert and -1 on delete, inside the same transaction.
(c) Failure modes: (1) a follow inserted without firing the trigger → drift; (2) concurrent follows racing to update the same counter → lost updates (fix with an atomic count = count + 1, not read-modify-write); (3) double-firing on retries → over-count. A periodic reconciliation job that recomputes the true count is wise insurance.
(a) Left =fr/fw=3000/2500=1.2. Right =Csync/Cjoin=20/8=2.5. Since 1.2<2.5, the inequality fails → do NOT denormalize. Net Δ=3000⋅8−2500⋅20=24000−50000=−26000 units/day (a loss). On the map this workload sits left of the diagonal.
(b) Csync is high because every balance change must be atomic, durable, and auditable; a cached balance would need locking, transactional coupling, and reconciliation for regulatory correctness — expensive per write. And fw is nearly as large as fr, so the sync cost is paid almost as often as the saving.
(c) Keep the ledger as the single source of truth and compute the balance from it (optionally an indexed running total per account rather than a duplicated field). This is where Indexing beats denormalization: it speeds reads without introducing a second copy of the fact.
Recall Solution L5.2
(a) Δcompute=frCjoin−fwCsync=8000⋅12−300⋅90=96000−27000=69000 units/day.
(b) Δnet=Δcompute−S=69000−5000=64000 units/day → still strongly positive. Denormalize (build the view).
(c) The verdict is a clear yes: even after paying 5000/day for storage you net 64000/day. The knob to tune is refresh cadence. The dominant write cost is the refresh (fwCsync=27000/day); if you batch refreshes — say once/hour instead of on every underlying write — you cut the effective fw that drives sync cost, pushing Δ even higher, at the price of some staleness. Because this is a reporting query (an OLAP-style workload), slight staleness is acceptable, so trading freshness for a bigger net saving is the right move here.
Recall Solution L5.3
A good answer hits: (1) Normalize first — never start denormalized; measure to find an actually-slow hot read. (2) Estimate the read/write ratiofr/fw and the cost ratioCsync/Cjoin; denormalize only when the former clearly beats the latter (a tie, Δ=0, is not enough — the non-math costs break the tie toward "stay normalized"), and note that truly write-once data (fw=0) is an automatic yes. (3) Choose a guard mechanism matched to the freshness requirement — trigger/transaction for must-be-exact-now, scheduled refresh for tolerable staleness. (4) Consider whether Indexing or a materialized view solves it without duplicating a fact. (5) Add reconciliation/monitoring because unguarded duplicates will drift into anomalies.