The Materialized View Pattern: Precompute Now, Read Fast Later

2026-05-16

A materialized view is a query result stored as a physical table. Unlike a regular view (which re-executes its SQL every time you select from it), a materialized view holds the answer on disk. Reads become a simple table scan or index lookup instead of a 12-way join over a billion rows.

You reach for this pattern when:

Concrete example. An e-commerce site shows "Top 100 products this week" on its homepage. The honest query joins orders, order_items, and products, filters by date, groups, sums, and sorts — maybe 800ms on a warm cache. The homepage is hit 50,000 times an hour. That's 40 minutes of database CPU every hour just for one widget. Instead, define a materialized view top_products_weekly refreshed every 5 minutes. Each refresh runs the expensive query once; every page load reads 100 rows from an indexed table in under 2ms.

The refresh question is the whole game. Three common strategies:

Rule of thumb for sizing the refresh interval: set it to roughly 1/10th of the acceptable staleness window. If product owners say "an hour-old leaderboard is fine," refresh every 6 minutes. This gives buffer for failed refreshes and avoids the trap of "refresh exactly at the staleness boundary" — one missed run and you're serving stale data.

Pitfalls to watch:

Materialized views are caching, but with the database doing the work — which means transactional guarantees on the refresh and no separate cache layer to invalidate.

Key Takeaway: When a query is expensive and read far more often than its data changes, store the answer — not the question — and refresh it on a schedule that fits your staleness budget.

All newsletters