A plain view runs every time you select from it. A materialized view holds a snapshot on disk, which is fast to read and stale until you refresh it.
CREATE VIEW paid_orders AS
SELECT * FROM orders WHERE status = 'PAID'; -- re-runs each time
CREATE MATERIALIZED VIEW daily_revenue AS
SELECT created_at::date AS d, SUM(total) AS revenue
FROM orders GROUP BY 1; -- stored
REFRESH MATERIALIZED VIEW daily_revenue;
-- CONCURRENTLY avoids locking readers, and needs a unique index:
CREATE UNIQUE INDEX ON daily_revenue (d);
REFRESH MATERIALIZED VIEW CONCURRENTLY daily_revenue;
SELECT * FROM daily_revenue;
plain view -> 1,840 ms (full aggregate every time)
materialized -> 2 ms (index scan on stored rows)
-- A plain REFRESH takes an exclusive lock for its whole duration.
-- CONCURRENTLY is slower but keeps the view readable throughout.
Run this yourself in the Online Java Compiler, spin up a live REST API in the API Sandbox, or practise with Java interview questions.
Published 2026-08-25