A view whose result set is physically stored on disk and can be refreshed on demand or automatically. Trades storage and staleness for query speed — avoids recomputing expensive aggregations on every query.
Physical snapshots of a query result stored as a table, refreshed on demand or on a schedule. Dramatically faster for expensive aggregations over large tables at the cost of stale data. The right choice when near-real-time accuracy is not required.
| Database System | Support Status | Since Version | Notes |
|---|---|---|---|
| MySQL | ✗ Not Supported | — | MySQL has no native materialized view. Common workarounds: (1) a regular table populated by a scheduled event or stored procedure; (2) a STORED table populated by a trigger on the source table. MariaDB does not have materialized views either. |
| PostgreSQL | ✓ Supported | 9.3 | REFRESH MATERIALIZED VIEW rebuilds the view from scratch (locks table during refresh by default). REFRESH MATERIALIZED VIEW CONCURRENTLY (requires a UNIQUE index) allows concurrent reads during refresh. No automatic refresh — use pg_cron, a trigger, or an external scheduler. Can be indexed like a regular table. |
| SQL Server | ✓ Supported | 2000 | Called indexed views. Create a regular view, then add a UNIQUE CLUSTERED INDEX — SQL Server automatically maintains the stored result on DML changes (synchronous, not on-demand). Requires the view to be created WITH SCHEMABINDING and imposes restrictions: no subqueries, no OUTER JOINs (Enterprise Edition relaxes some), no non-deterministic functions. The optimizer can use indexed views automatically (Enterprise) or with NOEXPAND hint (all editions). |
| Oracle | ✓ Supported | 8i | Full-featured materialized views with multiple refresh modes: COMPLETE (full recompute), FAST (incremental via materialized view logs), and FORCE (FAST if possible, else COMPLETE). Refresh can be ON COMMIT (synchronous) or ON DEMAND. The query rewrite feature lets Oracle's optimizer automatically use a materialized view instead of the base tables when it detects a matching pattern. |
| SQLite | ✗ Not Supported | — | SQLite has no materialized view support. The standard workaround is to create a regular table and populate it manually or via a trigger. |
The concept is consistent but implementations vary enormously. SQL Server's indexed views are automatically maintained on every DML — no REFRESH command exists. Oracle supports incremental (FAST) refresh via materialized view logs, avoiding full recomputes. PostgreSQL's REFRESH is always a full recompute; CONCURRENTLY mode avoids locking but needs a unique index. MySQL has no native support at all. Oracle's query rewrite feature is unique: the optimizer can transparently substitute the materialized view for the base tables in unmodified queries.
MySQL has no native materialized view. Common workarounds: (1) a regular table populated by a scheduled event or stored procedure; (2) a STORED table populated by a trigger on the source table. MariaDB does not have materialized views either.
REFRESH MATERIALIZED VIEW rebuilds the view from scratch (locks table during refresh by default). REFRESH MATERIALIZED VIEW CONCURRENTLY (requires a UNIQUE index) allows concurrent reads during refresh. No automatic refresh — use pg_cron, a trigger, or an external scheduler. Can be indexed like a regular table.
Called indexed views. Create a regular view, then add a UNIQUE CLUSTERED INDEX — SQL Server automatically maintains the stored result on DML changes (synchronous, not on-demand). Requires the view to be created WITH SCHEMABINDING and imposes restrictions: no subqueries, no OUTER JOINs (Enterprise Edition relaxes some), no non-deterministic functions. The optimizer can use indexed views automatically (Enterprise) or with NOEXPAND hint (all editions).
Full-featured materialized views with multiple refresh modes: COMPLETE (full recompute), FAST (incremental via materialized view logs), and FORCE (FAST if possible, else COMPLETE). Refresh can be ON COMMIT (synchronous) or ON DEMAND. The query rewrite feature lets Oracle's optimizer automatically use a materialized view instead of the base tables when it detects a matching pattern.
SQLite has no materialized view support. The standard workaround is to create a regular table and populate it manually or via a trigger.