Sign in
TodayMapLearnPracticeReview
Library
13 MINadvancedCloud ArchitectureNot started

Materialized View

A materialized view is a pre-computed, stored result of a query, refreshed periodically or on change. Unlike a regular SQL view (which is just a saved query re-executed on read), a materialized view holds actual data — so reads are fast (a single table scan or key lookup instead of a complex join) but writes bear the cost of keeping the view up to date. The pattern trades write cost and staleness for read speed and simplicity, and is the workhorse pattern behind every dashboard, every search index, and every read-optimized projection in a CQRS system.

Why this matters

Most real-world systems have asymmetric read/write ratios — often 100:1 or more. Running the same expensive join on every read wastes compute, slows user-facing queries, and limits scale. A materialized view computes the answer once and serves it from a fast store (the database itself, Redis, Elasticsearch), refreshing in the background. The result: p99 query latency drops from seconds to milliseconds, the database stops being the bottleneck, and the read tier scales independently. Every analytics dashboard, every search system, and every CQRS read model is a materialized view by another name.

Prerequisites
  • Denormalization
  • CQRS
Related
  • CQRS
  • Event Sourcing
  • Index Table
Used in

Foundational.

Lesson

How it works

A regular SQL view is a saved query — every time you read it, the database re-runs the query. A materialized view persists the query's result as actual rows in a table, so reads are fast (no re-computation). The trade-off: the view must be refreshed when underlying data changes.

Three refresh strategies:

1. On-demand (manual) — refresh when you say so. Used for nightly batch refreshes: at 2 AM, drop and rebuild the view from current data. Reads during the day are fast and consistent with the 2 AM snapshot. Stale, but predictably stale. Common for daily reports.

2. Scheduled (periodic) — refresh every N minutes/hours. Trade staleness for freshness. The view is at most N minutes behind. Used for near-real-time dashboards.

3. Incremental / event-driven — refresh on every write, or on every event. Most fresh, most expensive. Two flavors:

  • Synchronous: the write transaction also updates the view. Strongly consistent, but slower writes and harder to recover from failure.
  • Asynchronous: the write emits an event; a consumer updates the view. Eventually consistent, but decouples write and view latencies.

The right strategy depends on the query's tolerance for staleness and the write volume. A nightly sales report can tolerate 24-hour staleness; a leaderboard during a live game needs near-real-time.

Materialized views can live in:

  • The same database — native materialized views in PostgreSQL, Oracle; refreshed via REFRESH MATERIALIZED VIEW.
  • A different store — Elasticsearch index as a view of Postgres data; Redis cache as a view of a row; a denormalized table in a data warehouse as a view of operational data.
  • Multiple stores — one source, many views, each optimized for its read pattern (search, analytics, caching).

Choosing a refresh strategy is the core decision. Trade-offs:

Full rebuild — drop and recreate the view from scratch. Simple, correct, but expensive. Use when:

  • The view is small enough to rebuild in minutes.
  • Underlying data changes so much that incremental is barely cheaper.
  • The refresh runs nightly when traffic is low.

Incremental refresh — only update the rows that changed. Much cheaper for large views with small change sets. Use when:

  • The view is large (millions of rows) but only a small fraction changes per refresh.
  • You can identify which rows changed (via updated_at timestamp, CDC, or event sourcing).
  • You can correctly handle deletes (often the hard part).

Event-driven / streaming — every write emits an event; a consumer updates the view. Lowest staleness, highest write amplification. Use when:

  • Near-real-time freshness is required (seconds, not minutes).
  • The view is a projection of an event-sourced system.
  • You're already operating a streaming pipeline (Kafka, Flink).

Synchronous update in the write transaction — the write transaction also updates the view. Strongly consistent reads, slower writes, harder recovery. Use when:

  • Reads must be strongly consistent (no staleness acceptable).
  • Write volume is low enough that the extra cost is negligible.
  • The view fits in the same database (so the update is in the same transaction).

A subtle but important point: materialized views have schemas, and schemas evolve. When the view's definition changes, you may need to rebuild it from scratch — which can take hours for large views. Plan for this: version the view, rebuild in the background, switch over atomically.

Materialized View vs Cache

These are related but distinct. A cache stores the result of a query with no transformation — same shape, just faster. A materialized view stores a transformed, often aggregated, often denormalized version of the data, optimized for a specific query. A cache is invalidated on write (or expires on TTL); a materialized view is refreshed on a schedule or via events. Caches are usually per-row; materialized views are usually per-query or per-aggregate. Both trade freshness for read speed. In practice, the line blurs: a Redis cache of a denormalized user feed is both a cache (fast lookup) and a materialized view (transformed shape).

When to use materialized views:

  • Aggregations — sum, count, average over many rows. Pre-compute once, read many times. Dashboards, reports, leaderboards.
  • Denormalized reads — joins that are expensive at read time but cheap when pre-computed. ‘Get user with all their orders’ as one row instead of a join.
  • Different query patterns — relational store for writes, search index for full-text, graph for relationships. Each is a view optimized for its query.
  • Read-heavy workloads — 100:1 read:write ratio justifies the write amplification.
  • CQRS read models — projections of the write model, each shaped for its query.

When NOT to use materialized views:

  • Simple CRUD with low read volume — the overhead of refresh isn't worth it.
  • Strongly consistent reads required — materialized views are eventually consistent by nature.
  • Low write volume AND low read volume — just use the source directly.
  • High write volume with low read volume — the refresh cost dominates; don't materialize.
  • When the view is rarely queried — pay for refresh, never read. Delete it.

A common anti-pattern: materializing every possible query. Each materialized view costs write amplification, storage, and operational complexity. Materialize the queries that actually matter — the slow ones, the hot ones, the ones on the critical path.

Check yourself
interview

An analytics dashboard queries `SELECT SUM(revenue) FROM orders WHERE date = TODAY` on a table of 100M rows. Reads are slow. Which pattern is most appropriate?

Pick one answer.

Check yourself
interview

You have a materialized view refreshed nightly at 2 AM. A user updates their data at 10 AM and then queries their dashboard. What will they see, and what are the options?

Pick one answer.

Engineering mental model

Mental model. Think of Materialized View as a deliberate boundary in a system. The boundary exists because something becomes harder to manage when everything is done in one place: latency, scale, failure isolation, consistency, cost, or team ownership. The useful question is not “what does Materialized View mean?” but “what pressure makes this boundary worth introducing, and what new failure mode does it create?”

Design lens

Before choosing Materialized View, name the workload, the critical user path, the dominant bottleneck, the failure you are trying to absorb, and the trade-off you are willing to accept. If you cannot name those five things, the design is probably premature.

Original NO CAP systems visual for Materialized View.
Image unavailable. Original NO CAP systems visual for Materialized View.
Materialized View: a compact system-thinking visual.— Original NO CAP visual.
// Pseudocode
request = receive()
result = materialized_view(request)
return result

// Production questions:
// 1. What happens on timeout?
// 2. Can this operation be retried safely?
// 3. What is the bottleneck?
A minimal engineering sketch for reasoning about Materialized View.

Back-of-the-envelope reasoning

Numerical lens: write down traffic, payload size, read/write ratio, peak multiplier and durability target before choosing a component. The numbers should justify the architecture.

Interactive sandboxdeterministic

Interactive thought experiment: Materialized View

Change the variables below and predict what breaks first in Materialized View. The production lab can later reuse these same inputs.

System pressure6%
Try this

Change one variable at a time. Predict the failure mode first, then move the slider and see whether your mental model matches the simplified system response.

Hint

If you are stuck on Materialized View, start by drawing the request path and marking every network hop, stateful component, queue, cache and failure boundary. Then estimate where the system will saturate.

Check yourself
solid

You increase traffic by 10× in a system using Materialized View. What should you inspect first?

Pick one answer.

Check yourself
interview

Which statement is the safest engineering habit when using Materialized View?

Pick one answer.

Try this
interview

You have dashboards for traffic, latency, errors and saturation. You can change the architecture, but every change has operational cost.

Production scenario: your system uses Materialized View, traffic suddenly spikes, and p99 latency doubles. What is your first move?

Interview drill

Answer this without notes: When would you choose Materialized View, and when would you intentionally avoid it? Mention at least one bottleneck it addresses, one failure mode it introduces, and one alternative. Then quantify the workload you are designing for.

Engineering lens

A useful engineering lens for Materialized View: define the problem it solves, the simpler design that fails first, the constraint that forces you to introduce this concept, and the new failure modes the concept creates.

Numerical sanity check

Back-of-the-envelope reasoning beats fake precision. State your traffic, payload, concurrency and growth assumptions explicitly, then calculate enough to know whether the current architecture is orders of magnitude away from the target.

Check yourself
interview

Do not optimize for a memorized definition. Reason from the workload and failure mode.

Imagine the simplest version of a system using Materialized View. What breaks first as traffic grows by 10×, and what would you change before reaching 100×?

Pick one answer.

Trade-offs

What you gain, what you pay

Pros
  • +Reads are fast — pre-computed, often a single-row lookup.
  • +Read patterns can be optimized independently — denormalized, indexed, aggregated as needed.
  • +Read tier scales independently of the write tier.
  • +Multiple views support multiple query patterns from one source.
  • +Reduces load on the source of truth — expensive queries run at refresh time, not on every read.
Cons
  • −Writes bear the cost of keeping the view fresh — write amplification.
  • −Staleness — the view lags the source, by seconds to hours depending on refresh strategy.
  • −Operational complexity — now you operate the source AND the view(s) AND the refresh pipeline.
  • −Schema evolution is harder — changing the view definition requires a rebuild, which can take hours.
  • −Storage cost — the view duplicates data.
Failure modes

How this breaks in production

  • Refresh falls behind under high write volume — view becomes increasingly stale.
  • Refresh job fails — view is silently stale, reads return wrong data; needs monitoring.
  • Incremental refresh logic has a bug — view drifts from source; only full rebuild fixes it.
  • Schema mismatch — view's schema lags the source's after a migration.
  • Rebuild takes too long — large views can take hours to rebuild, blocking schema changes.
  • View becomes a SPOF — if the view store (Elasticsearch, Redis) dies, reads fail even though the source is up.
Common mistakes

Don't fall into these traps

  • •Materializing every query — each view has cost; materialize only the ones that matter.
  • •Choosing the wrong refresh strategy — too infrequent (stale) or too frequent (expensive).
  • •Not monitoring refresh lag — silent staleness causes user-visible bugs.
  • •Not having a rebuild strategy — when the view drifts or the schema changes, you must be able to rebuild from scratch.
  • •Treating materialized views as strongly consistent — they're eventually consistent by design.
  • •Forgetting read-your-writes — users see stale data after their own writes; route critical reads to the source.
Where you see it

Real systems using this

PostgreSQL materialized views — native support with `REFRESH MATERIALIZED VIEW`.Data warehouses (Snowflake, BigQuery, Redshift) — materialized views and aggregate tables for BI dashboards.Elasticsearch indexes — materialized views of source data, optimized for full-text search.Redis caches — materialized views of database rows, refreshed on write or TTL.CQRS read models — projections of write-side events.
Teardowns

How real systems implement this

  • PostgreSQL materialized views — Native support: `CREATE MATERIALIZED VIEW ... WITH DATA` persists the query result. `REFRESH MATERIALIZED VIEW` re-runs the query and replaces the data. `REFRESH ... CONCURRENTLY` allows reads during refresh. Used for pre-computing aggregates and denormalized reads.
  • Snowflake / BigQuery materialized views — Cloud data warehouses support materialized views with automatic incremental refresh — when source data changes, only the affected view rows are updated. Used heavily in BI dashboards where the same aggregate queries run repeatedly.
  • Elasticsearch indexes — An Elasticsearch index is a materialized view of source data, optimized for full-text and structured search. Source data (from Postgres, Kafka, etc.) is indexed into Elasticsearch; reads query the index, not the source. Refresh strategy is near-real-time (1-second default refresh interval).
Interview prompts

Practice saying it out loud

  • Q1What is a materialized view, and how does it differ from a regular view or a cache?
  • Q2Your analytics dashboard is slow because it aggregates 100M rows per query. How do you fix it?
  • Q3What are the refresh strategies for a materialized view, and how do you choose?
  • Q4After a user updates their data, they see stale data on their dashboard. What's happening, and how do you fix it?
  • Q5When should you NOT use a materialized view? Give concrete criteria.
Research

Further reading & references

System Design Primer
Open source
ByteByteGo — Scale from zero to millions
ByteByteGo
System Design Tutorial
GeeksforGeeks
System Design Roadmap
roadmap.sh
Cloud Architecture reference
Reference
Cloud Architecture reference
Reference
Cloud Architecture reference
Reference

Core explanations are original NO CAP material. External references are provided for deeper study and standards.

What next?

Mark as understood once the mental model clicks.

Next recommended

CQRS