Standard Views and Their Benefits/Limitations
corebeginnerA view is a stored, named SELECT query — querying the view re-runs the underlying query every time, always returning current data. It stores no data of its own, only the query definition, similar to a CTE that persists across statements rather than being scoped to one.
Think of it as
A view is exactly a named subquery that persists — the same relationship a CTE has to a single statement, but scoped to the whole database instead. Every time a view is queried, PostgreSQL substitutes its stored definition and executes the resulting combined query fresh, which is why a view always reflects current data (a real benefit) but also why a view built on an expensive query pays that same expense on every single read (a real limitation).
What we're doing: Create a view hiding a WHERE filter, then insert a new row and confirm the view reflects it immediately with no refresh step.
- 4–5
- active_customers stores only this query — no data of its own.
- 8
- A new row is inserted directly into the underlying table, not through the view.
- 9–10
- Querying the view again immediately shows Grace, since the view re-runs its query fresh every time.
id | name
---+------
1 | Ada
(1 row)
id | name
---+------
1 | Ada
2 | Grace
(2 rows)Why this works: active_customers has no storage of its own — PostgreSQL substitutes its stored SELECT definition into the query being run against it, so the second SELECT effectively executes SELECT id, name FROM customers WHERE deleted_at IS NULL fresh, against the customers table as it exists right now, which already includes Grace. This is the direct mechanical consequence of a view being a stored query rather than a stored result — there is no cache to go stale, and therefore nothing to refresh.
Assuming a view caches its result and needs manual refreshing
Wrong
Better
What you see: A developer writes application code to periodically "refresh" a plain view, or is confused when a view built on rapidly-changing data does not need any such step, because they are thinking of it like a materialized view or an external cache.
Why: A plain VIEW (as opposed to a MATERIALIZED VIEW) stores no result at all — confusing the two is an easy mistake since they share the word "view," but only the materialized kind involves any concept of staleness or refreshing. A plain view is, mechanically, indistinguishable in freshness from running its underlying query directly by hand every time.
- SELECT * FROM active_customers — a query against the view
- leads to View definition substituted
- View definition substituted — stored SELECT swapped in
- leads to Full query executed
- Full query executed — against the real, current data
View vs the query it wraps
Together
Remember: A view stores only its defining query, not any data — it always reflects current data with no refresh needed, but pays the full cost of its underlying query on every single read.
See also: materialized views · common table expressions

