Chapter 20 — Further Reading

The balance (everyone)

  • Articles on "normalization vs. denormalization trade-offs." Read several; the judgment is what matters. Pair with Chapter 19 so you hold both directions at once.
  • "When to denormalize" practitioner posts — concrete signals (read/write ratio, hot aggregations) and cautionary tales of drift (Case Study 2).
  • Martin Kleppmann, Designing Data-Intensive Applications — chapters on data models and on derived data; an excellent treatment of when precomputation/denormalization is the right call.

Techniques (💻 Developer · 🏗️ DBA)

  • Materialized views & refresh strategies (PostgreSQL docs + pg_cron) — the preferred, managed denormalization (Case Study 1).
  • Trigger-maintained aggregates — patterns for keeping counts/totals correct across all write paths, including cascades (Case Study 2's Option B).
  • "Counter tables" and high-write counters — advanced patterns for maintaining counts under heavy concurrent writes (ties to Chapters 26–27).

Analytics & warehousing (📊 Analyst) — pairs with Chapter 34

  • Kimball, The Data Warehouse Toolkit — dimensional modeling and star schemas: denormalization as the correct default for analytics, with the reasoning.
  • OLTP vs. OLAP explainers — why transactional schemas normalize and analytical schemas denormalize.

Performance first (🏗️ DBA) — pairs with Chapter 23

  • "Index before you denormalize." Reinforces the professional sequence — an index often removes a read bottleneck with no redundancy. Read after Chapter 23.
  • Markus Winand, use-the-index-luke.com — many "slow query" problems are index problems, not modeling problems.

Reference (this book)

  • Chapter 15 — Materialized Views: the managed denormalization tool.
  • Chapter 23 — Indexing: the lower-risk first resort for read speed.
  • Chapter 34 — Data Warehousing: denormalized star schemas in depth.
  • Appendix I — SQL Cookbook: maintained-aggregate and summary-table recipes.

Do, don't just read

  • Build Case Study 1 on Mercado: a product_review_stats matview + scheduled refresh; compare query speed to the live aggregation (on generate_data.sql).
  • Reproduce Case Study 2's drift: add a hand-maintained count, then delete rows via a cascade and watch the count go wrong. Fix it with a trigger.
  • Practice the sequence: for one slow read, try an index first, and only denormalize if the index doesn't suffice.

Next: Chapter 21 — Data Modeling Patterns: reusable solutions to recurring design problems.