Materialized Views: Caching Aggregations for Speed
Don't compute the total sales across 500 million rows every time a user refreshes a dashboard. Learn how to persist aggregations to disk using Materialized Views, and how to update them instantly using Fast Refresh.
The Recomputation Problem
Imagine you have a dashboard that shows the "Total Sales by Store for the Year." The underlying SQL query aggregates 2 billion rows from the TRAN_DATA table.
Every time a user opens the dashboard, the database performs a massive SUM() and GROUP BY operation, burning massive CPU and taking 45 seconds to load.
A Standard View won't help, because a standard view is just a macro for a SQL query—it still executes against the base tables every time.
A Materialized View (MView) solves this. It runs the query once, and actually creates a physical table on disk to store the results. When the user queries the MView, it returns instantly because the aggregation is already done!
Creating a Materialized View
Creating an MView is as simple as defining a query and a refresh schedule.
BUILD IMMEDIATE: Populates the view right now.REFRESH COMPLETE: When refreshed, it deletes all data and re-runs the full 2-billion-row query.ON DEMAND: Only refreshes when a DBA explicitly callsDBMS_MVIEW.REFRESH.
Refresh Strategies (Complete vs Fast)
A Complete refresh of a massive table is agonizingly slow. If only 500 new sales occurred today, why recalculate the billions of historical sales?
Fast Refresh to the rescue.
A Fast Refresh uses a Materialized View Log on the base table. This log acts like a trigger, recording exactly which rows were inserted, updated, or deleted since the last refresh. When you trigger the refresh, Oracle only processes the delta (the 500 new sales) and adjusts the aggregates (e.g., adding to the SUM() and COUNT()).
Step 1: Create the MView Log
Step 2: Create the Fast Refresh MView
ON COMMIT Overhead
REFRESH FAST ON COMMIT means every transaction that modifies the base table must wait for the MView to update before the commit succeeds. In a high-throughput OLTP system, this causes massive contention. It is safer to use ON DEMAND and refresh it via a scheduled job every 5 minutes.
The Magic of Query Rewrite
You have built mv_sales_by_store. But your BI tool (like Tableau) doesn't know about it. The BI tool is hardcoded to query the base sales table. Do you have to rewrite all your reports?
No! Enable Query Rewrite.
When a user executes:
The Cost-Based Optimizer intercepts the query. It realizes, "Wait, this aggregation perfectly matches mv_sales_by_store!" It secretly rewrites the user's query behind the scenes to select from the MView instead. The BI tool gets the result instantly without changing a single line of its code.
Common Gotchas
Important Gotchas
- !
If the base table has been updated, but the MView has not been refreshed yet, the MView is considered "Stale". By default, the CBO will not rewrite queries to use a Stale MView (to ensure data accuracy). You can override this if your business tolerates slightly old data by using
ALTER SESSION SET QUERY_REWRITE_INTEGRITY = STALE_TOLERATED;. - !
You cannot use
FAST REFRESHif your query contains certain complex operations likeUNION, outer joins, or non-deterministic functions (likeSYSDATE). Oracle will throw an error when you try to create it.
Key Takeaways
Key Takeaways
- Materialized Views store the physical results of a query on disk, acting as pre-computed aggregation caches.
- Use Materialized View Logs to enable FAST REFRESH, which dramatically reduces refresh times by only processing delta changes.
- Enable Query Rewrite so the database optimizer can transparently redirect heavy user queries to your optimized MViews.


