Chapter 19 · Materialized Views, Aggregate Tables, Cubes, and Precomputation

When Precomputation Beats Repeated Raw Fact Scans: Latency, Freshness, and Maintenance Cost

Decide when repeated atomic scans justify precomputation by measuring work reduction while making freshness, refresh cost, storage, lineage, and stale-read risk explicit.

Intermediate → Advanced140–175 minutesPrecomputation decision + stale-read labPython 3.13.5 · SQLite 3.46.1 · local/syntheticLast reviewed: September 2026
Continuity and explicit migration

Chapter 19 begins from the Chapter 18 accepted current-state controls: 9 paid lines, 7 orders, 11 units, 740 USD GMV, 450 USD cost, and 290 USD gross profit. The atomic grain remains one current paid order line. Precomputation never replaces or rewrites that atomic fact. Later in the lab, source sequence 207 deliberately introduces one new paid line (O1010/1, 80 USD GMV, 45 USD cost) so the base truth becomes 10 lines, 8 orders, 12 units, 820 USD GMV, 495 USD cost, 325 USD gross profit. That change is an explicit Chapter 19 fixture extension used to demonstrate stale acceleration and refresh.

Lab contract

Mandatory runtime: Python standard library plus SQLite; generation evidence used Python 3.13.5 and SQLite 3.46.1. Environment: local filesystem/in-process database; no managed service or paid feature. Storage: SQLite tables; because SQLite has ordinary views but no native materialized-view command, agg_daily_product is an explicitly managed materialized equivalent table. Time: AtlasMart business dates are UTC dates and refresh timestamps are UTC ISO-8601 strings. Keys: atomic sales key is (order_id,line_no); aggregate key is (order_date,product_id). History: this chapter does not change SCD rules; it accelerates the current paid-sales fact. Security: synthetic identities only. Benchmark cache: two warm-ups and seven measured executions; OS cache is not flushed. Non-guarantee: local timings do not predict cloud latency or billing.

Learning outcomes

01

Explain precomputation as persisted work rather than a magical faster query path.

02

Measure query work and maintenance/freshness cost on the same semantics.

03

Demonstrate a stale read and state which consumer contract allows or rejects it.

04

Choose precomputation only when workload evidence justifies additional operational state.

1. AtlasMart’s problem: the answer is correct, but the repeated work is expensive

After Chapter 18, AtlasMart knows how to reduce the work of scanning its atomic fact through projection and data skipping. That does not eliminate every expensive repeated aggregation. The sales dashboard repeatedly asks for GMV and units by date and product. If hundreds of consumers repeatedly scan the same atomic rows and regroup them, the warehouse can choose to precompute some of that deterministic work. Precomputation means persisting a result derived from governed base data so later reads can do less work.

The decision is not “materialized views are fast.” It is: is the repeated read work large and frequent enough to justify another persisted object with refresh, lineage, security, testing, storage, invalidation, and ownership obligations? The consumer needs low latency, finance still needs atomic drill-down, and operations need a freshness contract that tells them whether a cached aggregate is allowed to lag.

2. Three costs move in opposite directions

Decision surface Atomic scan Precomputed path What must be measured
Read latency/work Repeated grouping of base rows Fewer pre-grouped rows Rows/bytes scanned, plan, warm/cold latency distribution
Freshness Sees committed base data immediately May lag until refresh base watermark vs acceleration watermark, refresh age, SLO
Maintenance No extra refresh object Build/refresh/invalidate/test refresh CPU/I/O, lock/concurrency effects, retry/recovery
Storage Atomic fact only Atomic + derived object(s) bytes and retention, not “it is just a view” assumptions
Semantics One governed formula path Risk of duplicate business logic metric contract/hash and reconciliation

A normal SQL view saves query text, not necessarily query work. A persisted aggregate or materialized view saves work because data is stored. Product behavior varies: PostgreSQL 18 materialized views persist rows and can be explicitly refreshed, while the mandatory SQLite lab below manages an equivalent table itself. That implementation difference does not change the logical requirement to declare grain, freshness, and lineage.

3. Evidence: same query semantics, radically different row counts

The Chapter 18 deterministic scale-up produces 216,000 paid order-line benchmark rows. Grouping once by date and product produces 731 aggregate rows. Both queries below answer the same date-window/product totals. In the generation environment, the base query had a median of 23.256 ms; the aggregate query had a median of 0.045 ms. Those timings are evidence for this local run only. The more portable mechanism evidence is that one plan scans a 216,000-row fact while the other scans a 731-row aggregate and both return identical results.

generation_benchmark.txt
fact rows: 216000aggregate rows: 731base median: 23.256 msaggregate median: 0.045 msbase plan: [[7, 0, 0, 'SCAN f'], [14, 0, 0, 'USE TEMP B-TREE FOR GROUP BY']]aggregate plan: [[7, 0, 0, 'SCAN a'], [12, 0, 0, 'USE TEMP B-TREE FOR GROUP BY']]result equality: PASSNOTE: timings are generation-environment observations, not portable guarantees.

Do not use this ratio as a cloud cost estimate. Cache, vectorization, distributed shuffle, concurrency, storage format, partition pruning, and billing units can dominate on another engine. Re-run the same semantic corpus on the target platform.

4. Controlled failure: “materialized” does not mean “current”

At source sequence 206, AtlasMart builds agg_daily_product and records watermark 206. Then source sequence 207 inserts O1010/1 for 80 USD GMV and 45 USD cost. The atomic fact is immediately 820 USD GMV, while the untouched acceleration object still says 740. A dashboard routed blindly to the aggregate is now wrong by 80 USD relative to current truth.

stale-read acceptance trace
canonical before Chapter 19 extension: 9 lines / 7 orders / 11 units / $740 GMV / $450 cost / $290 profitfresh aggregate before change:            9 lines / 11 units / $740 GMV / $450 cost / $290 profitbase after unrefreshed seq-207 insert:     10 lines / 8 orders / 12 units / $820 GMV / $495 cost / $325 profitstale aggregate after insert:              9 lines / 11 units / $740 GMV / $450 cost / $290 profitstaleness gap:                              $80 GMVstate before repair:                        watermark 206, status=staledirty aggregate key:                        (2026-09-22, P100)aggregate after incremental refresh:        10 lines / 12 units / $820 GMV / $495 cost / $325 profitrefresh rerun:                              0 dirty keys; aggregate hash unchangedsemantic contract hash:                     9a7b963a31b049bbe64a822b6a2dd9549f43b2732222cfac29cd600c0bf9a747
Wrong approach

“The aggregate query succeeded, therefore the dashboard is fresh.” Query success proves only that stored rows were readable. It says nothing about whether dependencies changed after the last refresh. Freshness is a data-state property, not a task-success synonym.

5. A practical precomputation decision rule

Use workload evidence rather than a universal threshold. Estimate a review-period budget such as reads_per_period × work_saved_per_read, then compare it with refresh work, storage, invalidation complexity, and freshness risk. The units can be rows, bytes, CPU-seconds, warehouse credits, or dollars only when the engine exposes trustworthy measurements. The rule is intentionally economic rather than vendor-specific.

Precompute when the query shape is common, the higher grain can answer it without semantic loss, refresh can meet the consumer’s freshness requirement, and the derived object is operationally owned. Do not precompute when query shapes are highly diverse, atomic latency already meets the SLO, source updates make invalidation disproportionately hard, or the only justification is “cubes are standard.”

6. Reproducible local probe

Run python ch19_lab.py from a writable directory. The complete script is supplied in Lesson 5; this chapter excerpt shows the aggregate physical contract.

aggregate table contract
CREATE TABLE agg_daily_product(  order_date TEXT NOT NULL,  product_id TEXT NOT NULL,  line_count INTEGER NOT NULL,  order_count INTEGER NOT NULL,  units INTEGER NOT NULL,  gmv_cents INTEGER NOT NULL,  cost_cents INTEGER NOT NULL,  profit_cents INTEGER NOT NULL,  refreshed_through_seq INTEGER NOT NULL,  refreshed_at TEXT NOT NULL,  semantic_contract_hash TEXT NOT NULL,  PRIMARY KEY (order_date, product_id));

Reset with rm -rf atlasmart_ch19_lab on shells that support it, or delete that directory manually on Windows. Re-running the complete script recreates the database deterministically.

7. Production judgment

  • Correctness: acceleration cannot redefine the paid-sales filter, grain, currency, or profit formula.
  • Freshness: expose base watermark, acceleration watermark, refresh timestamp, and status to routing/monitoring.
  • Idempotency: a refresh retry at the same watermark must converge to the same semantic rows/hash.
  • Security: aggregated data can still be sensitive; derived objects need equivalent policy boundaries.
  • Observability: record query work, refresh work, result reconciliation, stale duration, failures, and consumer routing.
  • Rollback: atomic facts remain authoritative, so consumers can route back to the base calculation if the accelerator is stale or corrupt.

8. Bridge to aggregate fact design

Precomputation is useful only after its result has a precise business grain. Lesson 2 designs that grain and shows why GMV can reconcile through a daily/product aggregate while enterprise distinct order count cannot be obtained by simply summing per-group distinct counts.

Knowledge check

Check your understanding

  1. What additional state does precomputation introduce?
  2. Why is a successful aggregate query not freshness evidence?
  3. What is more portable than the observed local latency ratio?
  4. When should AtlasMart fall back to atomic facts?
Review the answers

1. Persisted derived rows plus refresh/invalidation metadata, lineage, ownership, tests, and storage.

2. The rows may have been computed before a newer base commit.

3. Same-result proof plus the measured reduction in rows/bytes/work at the declared grain.

4. When freshness, coverage, security, semantic-version, or reconciliation contracts for the accelerator are not satisfied.

Authoritative references

Keep knowledge open

Help the academy stay free and grow.

If these tutorials save you time, a small donation supports new lessons, technical review, diagrams, examples, and long-term maintenance.

ETHEthereum / ERC-20 only
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0

Send only Ethereum or ERC-20 compatible assets to this address.