Table of Contents

What Is a Materialized View? Benefits, Use Cases & Best Practices

Hao Wu
Software Engineer
|
July 24, 2026

Every query a database executes is a question answered at read time: the engine scans, joins, and aggregates whatever the query touches, and the person waiting pays for all of it. A materialized view moves that work earlier. The database runs the query ahead of time, stores the result physically, and serves reads from the stored copy. The trade is explicit: reads get faster and cheaper, and in exchange the results are only as fresh as the last refresh, the copy takes storage, and someone has to decide when and how it gets updated.

That trade, compute at read time versus compute ahead of time, is the whole subject. This post defines materialized views, walks through how they work, compares them with standard views and with plain tables, and covers the benefits, the main use cases, and the refresh strategies that determine whether one helps or quietly serves stale numbers. It closes with how the major databases differ and when a materialized view is the right tool.

What is a materialized view?

A materialized view is a database object that stores the result set of a query as physical rows. It is defined the same way a standard view is, with a SELECT statement over one or more base tables, but where a standard view stores only the query definition, a materialized view also stores the query’s output. Reading from it does not re-execute the defining query; it scans the stored rows, which can be indexed, partitioned, and optimized like any other stored data.

The concept comes out of the data warehousing and replication work of the 1990s. Oracle shipped the feature first under the name snapshots, as a way to replicate data between sites, and later renamed it materialized views as the emphasis shifted toward precomputing expensive aggregations. Most major relational databases and cloud warehouses now offer some form of the feature, though the semantics differ enough that the name alone tells you little about freshness guarantees or maintenance cost; the section on database support below covers the differences.

The defining characteristic to hold onto: a materialized view is a cache with a schema and a lineage. The database knows exactly which query produced the stored rows, which is what lets it refresh them, and in some systems transparently rewrite other queries to use them.

How does a materialized view work?

Creating a materialized view looks almost identical to creating a standard view. In PostgreSQL:

CREATE MATERIALIZED VIEW daily_revenue AS
SELECT order_date,
       SUM(amount)   AS revenue,
       COUNT(*)      AS order_count
FROM orders
GROUP BY order_date;

At creation time, the database executes the defining query once and writes the result to storage. From that point on, SELECT * FROM daily_revenue reads stored rows; the orders table is not touched. Because the result is physical, you can index it:

CREATE UNIQUE INDEX ON daily_revenue (order_date);

The stored rows do not update themselves when orders changes. They represent the state of the base tables at the moment the view was last populated, and they stay that way until a refresh re-runs the defining query:

REFRESH MATERIALIZED VIEW daily_revenue;

Refresh is where implementations differ most, and the refresh strategies section below covers the options. The other mechanism worth knowing at this stage is query rewrite: in some systems (Oracle and BigQuery among them), the optimizer notices that a query against the base tables could be answered from a materialized view and silently redirects it, so the view accelerates existing workloads without anyone changing application SQL. PostgreSQL does not do this; queries must name the materialized view directly.

Two-column diagram. Left, standard view: a query expands the view definition and scans the base tables at read time. Right, materialized view: a query scans the stored result, and a refresh arrow re-runs the defining query from the base tables.
Figure: A standard view pays the query cost at every read and is always current; a materialized view pays at refresh time, and its reads are fast but only as fresh as the last refresh.

The mental model that survives across all implementations: a materialized view is a stored query result plus a contract about how it gets updated. Everything else, indexing, rewrite, incremental maintenance, is an elaboration of those two parts.

Materialized view vs. standard view

A standard view and a materialized view are both named queries, and confusing them is easy because the CREATE statements differ by one keyword. What differs is when the compute happens and what can go wrong.

Standard View Materialized View
What Is Stored The query definition only The definition plus the query's result set
Freshness Always current; each read runs against live base tables As of the last refresh
Read Cost The full cost of the underlying query, every time The cost of scanning stored, indexable rows
Write-side Cost None Refresh compute, and change tracking where supported
Storage Negligible Proportional to the result set
Failure Mode Slowness surfaces immediately, at read time Staleness surfaces silently, in downstream numbers

The last row is the one experienced engineers weigh most. A standard view that wraps an expensive query fails loudly: the dashboard is slow, someone complains, the cause is found at read time. A materialized view fails quietly: the dashboard is fast and wrong, because a refresh job died three days ago and nothing that reads the view can tell. Choosing a materialized view means taking on monitoring of the refresh path as a production responsibility, in exchange for taking read latency off the table.

Materialized view vs. table

The comparison that matters most in practice is materialized view versus the thing teams usually build instead: a plain table maintained by a pipeline. Every data platform has these, a daily_revenue_summary table populated by a nightly job, and they are materialized views implemented by hand.

Pipeline-maintained Table Materialized View
How Contents Arrive ETL jobs or application writes The database evaluates the defining query
Lineage Lives in pipeline code, opaque to the database Declared in the view definition, known to the database
Drift Risk Transformation logic drifts from what consumers assume it is The definition is the single statement of the transformation
Writability Fully writable, including by mistake Read-only; contents change only by refresh
Refresh Machinery Whatever the pipeline implements, tested by the team Built into the database, tested by the vendor
Flexibility Any transformation code can produce it Limited to what the database allows in a view definition

The synthesis: a materialized view is a summary table whose maintenance contract the database enforces. The defining query cannot drift from the stored contents, no one can UPDATE a row by hand during an incident and leave it inconsistent, and the refresh machinery is vendor code rather than team code. The pipeline-maintained table earns its place when the transformation exceeds what a view definition can express: procedural logic, external systems, a sequence of intermediate steps. When the transformation is a query, the materialized view is the stricter and cheaper contract; when it is a program, it needs a pipeline.

Benefits of using materialized views

Query performance on repeated work. The core benefit is arithmetic: a query that aggregates millions of rows into hundreds runs once at refresh time instead of once per read. Dashboards, reports, and APIs that ask the same expensive question many times a day stop paying for the same scan and join work on every request. In systems with query rewrite, the acceleration is also transparent: the optimizer redirects matching queries automatically, so a well-chosen materialized view can improve a whole class of existing reports without anyone rewriting them.

Predictable read latency. Because reads scan a precomputed result, latency stops depending on the size and current load of the base tables, which matters for anything with a latency budget, user-facing pages especially.

Reduced load on base tables. Analytical reads move off the operational tables and onto the stored copy. This is a form of workload isolation: the OLTP path stops competing with reporting scans for the same I/O and locks, without standing up a separate replica.

Cost control in cloud warehouses. Engines that bill by data scanned or compute time make the arithmetic visible in the invoice: scanning a small precomputed result instead of re-aggregating raw events converts directly into lower per-query cost.

Simpler queries for consumers. A materialized view names a business concept: daily_revenue rather than a forty-line join with aggregation. Consumers query the concept without knowing or repeating the underlying logic, and the logic has exactly one definition to review and change.

These benefits share a precondition worth stating: they apply to work that repeats. A materialized view accelerates the query shapes it precomputed and nothing else, so the benefit scales with how concentrated the workload is on those shapes. An ad hoc analytical environment where every query is novel gets little from the feature; a dashboard fleet hammering the same aggregates gets a lot.

Use cases for materialized views

Dashboards and BI aggregation. The canonical case: dashboards ask the same aggregate questions on every page load, the fact tables are large, and staleness of minutes to hours is acceptable. Materializing the aggregates turns each page load from a warehouse scan into an indexed lookup.

Read-optimized shapes for APIs. Services that serve denormalized reads, a product page assembling data from a dozen normalized tables, can materialize the joined shape once rather than joining per request. The application reads one wide row instead of orchestrating the join, and the normalization of the source tables is preserved.

Pre-joining across large tables. Some joins are expensive enough, large fact table to large fact table, that they dominate every query that includes them. Materializing the join once lets many downstream queries start from the joined result.

Warehouse rollup layers. The staged rollups of a warehouse, raw events to hourly to daily to monthly, are a chain of materialized views whether or not they use the feature. Using actual materialized views for the chain gives the database the lineage, so refreshes cascade in order and the definitions cannot drift apart.

Replication and distribution. The original Oracle use case still applies: a materialized view can hold a local, periodically refreshed copy of data whose source of truth is elsewhere, such as a reference dataset from another team’s database. Reads stay local; the refresh schedule bounds staleness.

The list is varied, but the shape underneath is constant: results read far more often than their inputs change, by consumers who can tolerate a bounded staleness window. A workload missing either half of that shape is better served by the alternatives in the sections that follow.

Refresh strategies for materialized views

Refresh strategy is where materialized views are won or lost operationally, because it fixes both the staleness window and the ongoing compute bill.

Complete refresh re-runs the defining query and replaces the stored result wholesale. It is simple, always correct, and supported everywhere, but its cost is proportional to the base data, not to what changed. Refreshing a year of aggregates because one day of orders arrived is affordable at small scale and ruinous at large scale. PostgreSQL’s REFRESH MATERIALIZED VIEW is a complete refresh; its CONCURRENTLY variant (which requires a unique index on the view) recomputes without locking readers out during the rebuild.

Incremental refresh applies only the changes since the last refresh. The database tracks deltas on the base tables, Oracle does this with materialized view logs, and folds them into the stored result. Cost becomes proportional to change volume, which is what makes frequent refresh affordable on large data. The constraint is that not every query shape can be maintained incrementally; each system documents which constructs (certain joins, aggregates, window functions) force a fall back to complete refresh.

On-commit refresh updates the view within the transaction that changes the base table. The view is never stale, and every write pays the maintenance cost at commit time. This couples write latency to view maintenance and suits views that must be transactionally consistent with their sources, not high-churn tables.

Scheduled and on-demand refresh decouple the view from writes entirely: a cron expression or an orchestrated job (dbt runs, Airflow DAGs) triggers refresh, or a human does. The staleness window is explicit and controllable, which is often exactly what reporting workloads want: numbers as of 6 a.m., stable all day.

Automatic background refresh is the managed-warehouse approach: the platform watches the base tables and refreshes on a best-effort basis with its own compute, as BigQuery and Snowflake do. It removes the operational burden and replaces it with a billing line and a freshness guarantee that is probabilistic rather than scheduled.

The strategy choice reduces to one question asked honestly: what staleness can the consumers of this view actually tolerate? Answering “none” is expensive, since it forces synchronous maintenance and taxes every write; most reporting workloads, when pressed, tolerate minutes to hours. The failure mode to design against is not choosing a window but forgetting to monitor it: whatever the strategy, something should alert when the view’s freshness falls outside the window the consumers agreed to.

Materialized views across popular databases

The feature’s name is standard; its semantics are not. What follows are the durable design-level differences, with links to each system’s documentation for the current details.

PostgreSQL has had native materialized views since 9.3. Refresh is manual and complete: REFRESH MATERIALIZED VIEW re-runs the whole query, with the CONCURRENTLY option to avoid blocking readers. There is no built-in incremental maintenance, no automatic refresh scheduling, and no query rewrite; teams pair the feature with cron or an orchestrator.

MySQL has no native materialized views in the core server (Oracle’s HeatWave analytics service added them separately). The standard substitute is a summary table maintained by triggers, scheduled events, or application code, which works but hands the team every responsibility the feature would otherwise carry.

Oracle originated the feature and still has the most complete implementation: materialized view logs for incremental (fast) refresh, on-commit and on-demand modes, and query rewrite that transparently redirects matching queries. Most of the vocabulary the industry uses for materialized views is Oracle’s.

SQL Server takes a different design under a different name: an indexed view is a view made physical by building a unique clustered index on it, after which the engine maintains it synchronously as part of every transaction that touches the base tables. There is no refresh concept and no staleness window; the cost is paid on the write path instead, and the defining query faces significant restrictions. Editions differ in whether the optimizer uses indexed views automatically.

Snowflake offers materialized views as an Enterprise Edition feature with a deliberately narrow definition surface: a view can reference a single table, with no joins. In exchange, maintenance is automatic; a background service keeps views current as base tables change, billed as serverless compute, and queries transparently combine the materialized rows with any not-yet-materialized changes so results stay current.

BigQuery provides automatically refreshed materialized views: refresh is triggered by base-table changes on a best-effort basis, computes incrementally where the view’s shape allows, and the optimizer can rewrite queries against base tables to read from a matching materialized view.

Databricks implements materialized views on Lakeflow declarative pipelines: the view is declared in SQL, and the pipeline engine decides per refresh whether it can apply changes incrementally or must recompute, based on the defining query’s shape and a cost model. It is the same complete-versus-incremental trade the older systems expose, moved into the platform’s decision rather than the user’s.

The pattern across the column: the older transactional databases make refresh the user’s problem and freshness explicit, while the cloud warehouses fold maintenance into the platform and bill for it. Neither end changes the underlying contract, a stored result that must somehow track its sources; the systems differ in who holds the pager for it.

When should you use a materialized view?

The decision reduces to four questions. First, does the same expensive query shape repeat? Materialization pays back per read; a query that runs once gains nothing. Second, can the consumers tolerate staleness, and how much? The answer sets the refresh strategy and much of the cost. Third, is the transformation expressible as a query the database will accept in a materialized view definition, within that system’s restrictions? If not, the pipeline-maintained table is the honest alternative. Fourth, is the team prepared to monitor freshness in production? A materialized view without freshness monitoring is an outage that has not happened yet.

When the answers line up, repeated reads, tolerable staleness, expressible transformation, monitored refresh, the materialized view is usually the cheapest correct tool. When they do not, the alternatives are a standard view (freshness over speed), a pipeline table (flexibility over enforcement), or a caching layer in the application (speed without database involvement, and with full responsibility for invalidation).

One workload deserves a specific warning: relationship traversal. Multi-hop questions, friends of friends, ownership chains through holding companies, lateral movement paths across machines, are join-heavy in a relational engine, and the reflexive fix is to materialize the joins. That works for a fixed depth and then stops scaling, and the reason is what a materialized view stores: the query’s output, which for a traversal grows with every hop. Each additional depth is another materialized join, row counts grow combinatorially, every copy adds its own staleness window, and an analyst who wants one more hop than was precomputed is back to the original slow query.

The alternative is an engine that does not materialize at all. PuppyGraph defines a graph schema over existing tables in SQL databases, data warehouses, and data lakes or lakehouses, including direct reads of open table formats like Iceberg and Delta Lake. The schema is a mapping, not a copy: no ETL into a graph database, no precomputed result whose size grows with query depth, and traversals run in openCypher and Gremlin at query time against the tables as they are. Where repeatedly scanning a source is slow or costly, an optional local table caches source rows on the compute nodes, the same kind of performance caching any query engine does.

Conclusion

A materialized view is a stored query result with an update contract: reads get the speed of precomputed data, and the team takes on the staleness window and the refresh machinery that come with it. It beats a standard view when the same expensive query repeats and current-to-the-second results are not required; it beats a hand-maintained summary table when the transformation fits in a query, because the database then enforces what pipeline code can only promise. The refresh strategy is the real design decision, and the honest version of the question is how stale the consumers can afford to be, answered before the feature is turned on and monitored after.

When the queries are novel, the data must be current, or the transformation is a program rather than a query, the alternatives are better tools. And for the one workload class where materializing never quite catches up, deep relationship traversal, the stronger move is an engine suited to the query shape over the source tables rather than a deeper stack of precomputed copies.

Try the forever-free PuppyGraph Developer Edition and book a demo with the team to see how openCypher and Gremlin queries run over warehouse and lakehouse tables, with no graph-specific ETL, and no materialized graph copy to keep fresh.

Hao Wu
Software Engineer

Hao Wu is a Software Engineer with a strong foundation in computer science and algorithms. He earned his Bachelor’s degree in Computer Science from Fudan University and a Master’s degree from George Washington University, where he focused on graph databases.

Get started with PuppyGraph!

PuppyGraph empowers you to seamlessly query one or multiple data stores as a unified graph model.

Dev Edition

Free Download

Enterprise Edition

Developer

$0
/month
  • Forever free
  • Single node
  • Designed for proving your ideas
  • Available via Docker install

Enterprise

$
Based on the Memory and CPU of the server that runs PuppyGraph.
  • 30 day free trial with full features
  • Everything in Developer + Enterprise features
  • Designed for production
  • Available via AWS AMI & Docker install
* No payment required

Developer Edition

  • Forever free
  • Single noded
  • Designed for proving your ideas
  • Available via Docker install

Enterprise Edition

  • 30-day free trial with full features
  • Everything in developer edition & enterprise features
  • Designed for production
  • Available via AWS AMI & Docker install
* No payment required