Stackbook Logo
scalingestablished · medium operational burden

Precomputation and Denormalization

Also known as: precomputed-views, read-optimized-models

Intent

Compute or duplicate data at write time so that reads become simple lookups.

Problem

Reads that join many tables or aggregate large datasets are slow and costly, and they repeat the same work for every request. The read path is far more frequent than the write path but pays for the complexity of the normalized model.

Forces

  • •Reads outnumber writes by a large factor
  • •Joins and aggregations scale poorly
  • •Duplicated data can drift from its source
  • •Users accept bounded staleness for derived values

Solution

Overview

Precomputation moves work from read time to write time, or to a scheduled job. Denormalization is the storage side: keeping redundant copies of data so queries need no joins.

How it works

order placed ──> orders table (source of truth)
      │
      └─ event/CDC ──> updater ──> customer_totals(customer_id, order_count, revenue)
                                   product_page_doc(product_id, price, rating, stock)

An updater consumes changes and maintains the read model. Increments should be idempotent: store the last processed event id or recompute from the source for the affected key. A nightly or weekly rebuild corrects any accumulated drift.

Choose the approach by freshness need. In-transaction updates give immediate consistency but couple write latency to the number of derived copies. Change-data-capture pipelines add seconds of delay with no impact on the writer. Batch jobs are cheapest and suit reports and rankings.

Precompute only what is hot. Measure the top queries by cost times frequency, then build projections for those. Everything else can stay on the normalized model, where flexibility is worth more than speed.

Pitfalls

  • Duplicating data without declaring a single source of truth.
  • Non-idempotent counters that double count on retries.
  • No reconciliation job, so errors persist for months.
  • Denormalizing early. Premature copies are hard to remove.
  • Updates that fan out to millions of derived rows, for example renaming a popular entity.

Key takeaways

  • Keep one authoritative model and treat projections as rebuildable.
  • Update derived data idempotently and reconcile regularly.
  • Match the update mechanism to the staleness users can accept.
  • Precompute only measured hot queries.

✓ When to Use

  • •Dashboards, feeds, counts and leaderboards
  • •Read-heavy endpoints with stable query shapes
  • •When joins across services or shards are too slow

✗ When Not to Use

  • •Ad hoc queries whose shape is unpredictable
  • •Data that changes faster than it is read
  • •When strong consistency of derived values is mandatory

Pros

  • +Very fast, cheap reads
  • +Predictable latency under load
  • +Isolates read model design from the write model

Cons

  • −Write path gets more work and complexity
  • −Derived data can become stale or inconsistent
  • −Storage cost and backfill effort grow

Cost Profile

Infrastructure

Extra storage and compute for pipelines

Operational

Medium: backfills and reconciliation

Cognitive

Medium: multiple representations of truth

Failure Modes

  • Derived data drifts after a missed update event

  • Backfill job overloads the primary database

  • Schema change in the source silently breaks the projection

Real-World Examples

Alternatives

    Related Patterns

    • materialized-view
    • cqrs
    • cdc

    Competency Domains

    data stateeconomics evolution