Materialized View Pattern
Pre-compute and cache query results as materialized views: build strategies, refresh mechanisms, consistency trade-offs, and use cases.
What Is a Materialized View?
A materialized view is a pre-computed, stored result of a query. Unlike a regular (virtual) SQL view which re-executes the underlying query on every access, a materialized view is physically stored on disk. When a query runs against it, the data is already computed — no joins, no aggregations, no full table scans.
The pattern extends beyond SQL databases. In distributed systems, materialized views appear as read-side projections in CQRS architectures, Redis caches pre-populated with aggregated data, Elasticsearch indexes that denormalize data from multiple source tables, and pre-built Cassandra tables designed for a specific query access pattern.
Refresh Strategies
The key trade-off in materialized views is between freshness and cost. You choose how frequently to refresh:
| Strategy | How It Works | Staleness | Use Case |
|---|---|---|---|
| Full refresh | Recompute entire view on a schedule | Up to schedule interval | Nightly reports, batch analytics |
| Incremental refresh | Apply only changed rows since last refresh | Up to schedule interval | Large views that change frequently |
| On-write (synchronous) | Update view in same transaction as base table write | Zero (always fresh) | Small views, critical consistency needed |
| Event-driven (async) | Subscribe to change events, update view asynchronously | Milliseconds to seconds | CQRS read projections, CDC-driven indexes |
| On-demand (lazy) | Rebuild view only when queried and stale TTL expired | Up to TTL | Infrequently accessed reporting views |
Materialized Views in CQRS
In a CQRS architecture, the read model is a materialized view. Every time a command produces an event, a projector updates one or more read-model tables. This lets you design each read table specifically for its query — no joins needed at query time.
Cassandra and the Materialized View Pattern
In Cassandra, data must be stored in the exact shape of the query (no joins at all). Teams often create multiple Cassandra tables for the same data — one partitioned by `userId`, another by `orderId`, another by `status`. Each is a materialized view of the same logical data, optimized for a different query. This is called the table-per-query approach and is idiomatic Cassandra design.
SQL Materialized Views
-- Create a materialized view of order summaries
CREATE MATERIALIZED VIEW order_summary AS
SELECT
o.id AS order_id,
u.name AS customer_name,
COUNT(i.id) AS item_count,
SUM(i.price * i.quantity) AS total,
o.status,
o.created_at
FROM orders o
JOIN users u ON o.user_id = u.id
JOIN order_items i ON i.order_id = o.id
GROUP BY o.id, u.name, o.status, o.created_at;
-- Refresh the materialized view (PostgreSQL)
REFRESH MATERIALIZED VIEW CONCURRENTLY order_summary;
-- Query is now a fast single-table scan
SELECT * FROM order_summary WHERE order_id = 12345;Consistency Considerations
Stale Reads Are Inevitable
Any materialized view that is not refreshed synchronously in the same transaction as the source write will be stale. Applications must be designed to tolerate this. Display last-updated timestamps in UIs for analytics views, and use event-driven refresh for views that must be nearly real-time.
When a materialized view is invalidated (source data changed), you have three options: mark-and-recompute (flag it as stale, compute on next read), eager refresh (recompute immediately in the background), or serve stale (return the old value with a cache-control hint). The right choice depends on how much staleness the consumer can tolerate.
Real-World Examples
- Twitter/X pre-computes follower timelines as materialized views in Redis — pulling a timeline is a fast list read, not a JOIN of 10,000 follows.
- Google BigQuery automatically maintains materialized views and refreshes them as source data changes, charging only for the delta computation.
- Airbnb uses Elasticsearch as a materialized view of listing data from Postgres, enabling full-text search and geo-queries that would be expensive in the relational DB.
- Shopify maintains denormalized product views in Elasticsearch for storefront search, kept in sync with the Postgres source via CDC.
Interview Tip
Interviewers love materialized views as a solution to read performance problems. When a system has complex join queries running slowly on hot paths, propose a materialized view maintained by CDC or event-driven projection. Always explain the refresh strategy and the staleness trade-off. A solid answer shows you understand that the view's freshness must match the business requirement — analytics tolerate minutes, while a user-facing balance cannot.