Skip to content

Materialized Views

A materialized view stores the result of a SELECT query as cached data. Unlike regular views (which re-execute the query on every access), materialized views serve from precomputed results and can be refreshed on demand, on a schedule, or automatically after each commit.

CREATE MATERIALIZED VIEW monthly_revenue AS
SELECT month, SUM(amount) AS total
FROM orders
GROUP BY month;

The view is populated immediately on creation. Subsequent reads return the cached result without re-executing the underlying query.

Re-execute the defining query and replace the cached data:

REFRESH MATERIALIZED VIEW monthly_revenue;

Create a view that refreshes automatically on a timer:

CREATE MATERIALIZED VIEW hourly_stats
REFRESH EVERY 3600
AS
SELECT status, COUNT(*) AS cnt
FROM orders
GROUP BY status;

The REFRESH EVERY <seconds> clause schedules a background task that re-executes the query at the specified interval.

Create a view that refreshes after every transaction commit:

CREATE MATERIALIZED VIEW live_totals
REFRESH ON COMMIT
AS
SELECT category, SUM(price) AS total
FROM products
GROUP BY category;

On-commit views are always up-to-date but add overhead to every write transaction. Use this strategy for dashboards that require real-time accuracy on small-to-medium tables.

StrategyTriggerTrade-off
ManualREFRESH MATERIALIZED VIEWFull control; data may be stale
PeriodicBackground timerBounded staleness; no write overhead
On CommitAfter each transaction commitAlways fresh; adds commit latency

Query a materialized view exactly like a table:

SELECT * FROM monthly_revenue WHERE month = '2025-03';
DROP MATERIALIZED VIEW monthly_revenue;
DROP MATERIALIZED VIEW IF EXISTS monthly_revenue;

The virtual table __pdb_stat_materialized_views exposes metadata for all materialized views:

SELECT * FROM __pdb_stat_materialized_views;
ColumnTypeDescription
nameTEXTView name
queryTEXTThe defining SELECT statement
strategyTEXTRefresh strategy (MANUAL, EVERY Ns, ON COMMIT)
last_refreshedBIGINTEpoch microseconds of last successful refresh
next_refreshBIGINTEpoch microseconds of next scheduled refresh
row_countBIGINTNumber of rows in the cached result
is_populatedTEXTWhether the view has been populated at least once

Refreshes are atomic from the perspective of concurrent readers — queries never see a partially-updated view. Periodic views are refreshed when their next-refresh timestamp elapses; ON COMMIT views refresh after each transaction that touches the underlying tables.