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

Materialized View Refresh Strategies, Incremental Refresh Concepts, and Dependency Management

Model materialized-view refresh as a governed dependency process, compare full and incremental refresh concepts, demonstrate a stale read, and repair only invalidated aggregate keys with idempotent replay.

Intermediate → Advanced150–185 minutesRefresh/invalidation/idempotency labWatermarks 206→207 · PostgreSQL 18 referenceLast 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

Separate native materialized-view features from the vendor-neutral refresh mechanism.

02

Compare full refresh with incremental/partition-local recomputation and track watermarks.

03

Use dependency/change evidence to invalidate only affected aggregate keys.

04

Prove refresh reruns are idempotent and stale state is visible rather than hidden.

1. Materialization is persisted query state plus a refresh contract

A materialized view is an engine-managed persisted result of a query on systems that implement that feature. PostgreSQL 18, for example, persists rows and later regenerates them with REFRESH MATERIALIZED VIEW. Other engines have different automatic/incremental refresh rules, eligibility restrictions, rewrite behavior, and concurrency semantics. SQLite has ordinary views but no native materialized-view command, so the mandatory lab uses an explicitly managed table. The vendor-neutral mechanism is the same: base dependencies change; the persisted result becomes stale until a refresh process makes it current to a defined watermark.

2. Full refresh versus incremental refresh

Strategy Mechanism Strength Boundary
Full refresh Recompute all aggregate rows from governed base truth. Simple correctness model; easy to reconcile. Can be expensive, slow, or disruptive at scale.
Delta arithmetic Apply +/− contributions from change events. Can minimize work. Updates, deletes, late corrections, and non-additive metrics are easy to mishandle.
Partition/key recompute Identify affected aggregate keys, delete/rebuild only those groups from base truth. Idempotent and simpler than hand-maintained deltas for many aggregates. Requires reliable dependency/change keys; a changed dimension may invalidate more than one fact partition.

The lab uses partition/key recomputation because it makes the correctness mechanism observable without pretending to emulate a proprietary incremental materialized-view engine.

3. Stale-read trace: base sequence 207, aggregate sequence 206

The full refresh records refreshed_through_seq=206 at 09:00 UTC. Sequence 207 arrives at 09:07 and is committed to fact_sales. The acceleration state is immediately marked stale. If a reader at 09:08 is allowed a 15-minute freshness SLO, policy could still permit the accelerator; if the report requires “through latest committed sequence,” it must route to base or wait for refresh. The data engineer must state which contract applies rather than silently choosing.

observable stale state
base:      watermark 207, GMV $820aggregate: watermark 206, GMV $740state:     stalefreshness gap: $80 for this fixturerefresh age: a timestamp observation, not proof that all dependencies are complete

4. Dependency-driven repair

change_log records which old and new aggregate keys each changed fact can affect. Sequence 207 dirties only (2026-09-22,P100). The refresh deletes that aggregate row and re-derives it from current base truth, then advances the acceleration watermark only after the transaction commits.

partition-local recompute
-- Conceptual partition-local recompute for dirty aggregate keys.-- The complete lab derives these keys from change_log between watermarks.DELETE FROM agg_daily_productWHERE order_date = '2026-09-22' AND product_id = 'P100';INSERT INTO agg_daily_productSELECT order_date, product_id,       COUNT(*), COUNT(DISTINCT order_id), SUM(quantity),       SUM(amount_cents), SUM(cost_cents), SUM(amount_cents-cost_cents),       207, '2026-09-21T09:10:00Z', :semantic_contract_hashFROM fact_salesWHERE status='paid'  AND order_date='2026-09-22'  AND product_id='P100'GROUP BY order_date, product_id;

The complete executable function discovers dirty keys between the old and requested watermarks. On an immediate rerun through sequence 207, it finds zero new dirty keys and the aggregate semantic hash stays unchanged. That is idempotent refresh behavior for this fixture.

5. Controlled wrong approaches

Wrong approach Failure Repair
Advance refresh watermark before aggregate commit Crash can claim sequence 207 while rows still represent 206. Refresh rows + metadata in one atomic transaction or use equivalent publish/swap semantics.
Only handle inserts Updates/deletes leave old group contributions behind. Track old and new aggregate keys or recompute changed partitions from base truth.
Refresh on a clock without dependency checks Upstream/base load may be late or partial. Gate on committed base watermark/manifest and quality certification.
Assume PostgreSQL CONCURRENTLY semantics are universal Other engines expose different restrictions/locking/rewrite behavior. Verify exact target-engine/version documentation and benchmark under representative concurrency.

6. Dependency graph and invalidation scope

AtlasMart’s simplified lineage is source CDC → fact_sales → agg_daily_product → certified sales dashboard. A new sales row invalidates one or more aggregate groups. A metric-definition change invalidates every accelerator built on the old semantic contract. A product-dimension label correction may require no measure recomputation if the aggregate stores only product_id, but a pre-joined aggregate containing product category may need broader rebuild. Invalidation scope follows actual lineage, not table names.

refresh state model
{  "object": "agg_daily_product",  "base": "fact_sales",  "grain": "one paid-sales aggregate row per order_date + product_id",  "measures": ["line_count", "units", "gmv_cents", "cost_cents", "profit_cents"],  "non_additive_warning": "order_count cannot be summed across product/date groups for global distinct orders",  "refresh": {    "mode": "incremental-partition-recompute",    "watermark": 207,    "freshness_slo_seconds": 900  },  "semantic_contract_hash": "9a7b963a31b049bbe64a822b6a2dd9549f43b2732222cfac29cd600c0bf9a747",  "owner": "Analytics Engineering",  "lineage": ["fact_sales -> agg_daily_product -> certified sales dashboard"]}

7. Production refresh judgment

  • Transaction boundary: publish new aggregate rows and watermark consistently.
  • Retry: rerun from the same base watermark must converge.
  • Late data: change evidence must identify historical groups that become dirty.
  • Schema evolution: contract-breaking base changes block refresh until mapping/semantics are approved.
  • Security: refresh identity needs only the privileges required to read governed inputs and publish its derived object.
  • Observability: record requested/committed watermarks, dirty-key count, rows rebuilt, duration, failures, and reconciliation.
  • Rollback: keep the last certified accelerator generation or route to atomic facts if the new generation fails validation.

8. Bridge to cubes and semantic acceleration

One daily/product aggregate is tractable. A cube-like system considers many grouping levels and dimension combinations. Lesson 4 shows why the power set grows quickly, why real dimensional spaces are sparse, and why workload-driven selection beats “materialize everything.”

Knowledge check

Check your understanding

  1. What does the acceleration watermark mean?
  2. Why is partition-local recompute attractive?
  3. When does a semantic-contract change force broad invalidation?
  4. What must be atomic with watermark advancement?
Review the answers

1. The highest governed base change sequence represented by the published aggregate.

2. It can be idempotent and handles inserts/updates/deletes by re-deriving affected groups from base truth.

3. When the persisted rows were calculated under the old metric/filter/grain definition.

4. Publication of rows that represent that watermark, plus corresponding refresh metadata.

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.