Real-time materialized views
Standard materialized views store precomputed query results for fast reads, but their data becomes stale the moment the base table changes. You must refresh them manually or on a schedule, which introduces data lag.
Real-time materialized views eliminate this lag. Each DML statement (INSERT, DELETE, UPDATE) on a base table triggers an incremental update to the view automatically — no manual refresh needed. Use this feature when the number of read operations is greater than the number of write operations and stale query results are not acceptable.
Choose the right view type
| View | Materialized view | Real-time materialized view | |
|---|---|---|---|
| Storage | None | Stores query results | Stores query results |
| Data freshness | Always current | Stale until refreshed | Always current |
| Read performance | Reruns query on every read | Fast (precomputed) | Fast (precomputed) |
| Write overhead | None | None (refresh is manual) | Triggers run on every DML |
| Best for | Simple queries, always-fresh data | Read-heavy workloads, tolerable staleness | Read-heavy workloads, freshness required |
Key concepts
| Term | Definition |
|---|---|
| Base table | A regular table referenced in the materialized view definition |
| Delta | The set of rows added or removed from the base table since the last view update |
| Refresh | Maintains the materialized view so that its data is consistent with the data obtained by querying the current base table based on the view definition |
| Apply delta | An incremental update that inserts or deletes calculated incremental data from the view to maintain data consistency between the view and the base table |
How it works
Creating a real-time materialized view:
PolarDB rewrites the view query and computes hidden columns needed for incremental maintenance.
A trigger is created on each base table to capture DML changes.
When the required conditions are met, unique indexes are created on the view to accelerate delta application.
Refreshing a real-time materialized view:
A DML statement on the base table fires the trigger.
The trigger captures the incremental data.
PolarDB calculates the delta based on the view definition and the captured data.
The delta is applied to the view, keeping it consistent with the base table.
Dropping a real-time materialized view:
The delta-refresh trigger is removed from the base table.
The view is dropped.
Limitations
The base table must be a regular table. Partitioned tables, inherited tables, and column store tables are not supported.
Only
INNER JOINis supported. Other join types are not supported.Only
IMMUTABLEfunctions are supported.Supported view definition elements: simple queries, projections,
DISTINCT, and the following aggregate functions:MIN,MAX,SUM,AVG, andCOUNT.The following query constructs are not supported: subqueries,
[NOT] EXISTS,[NOT] IN,LIMIT,HAVING,DISTINCT ON,WITH(CTE),ORDER BY, window functions,GROUPING SETS,CUBE,ROLLUP,UNION,INTERSECT, andEXCEPT.When
GROUP BYis used, all group-by columns must appear in the projection.
Performance considerations
Real-time materialized views improve read performance at the cost of write throughput. Every DML statement on a base table fires a trigger and updates the view, adding latency to write operations. The actual overhead depends on the view definition, write load, and the base table's structure and indexes.
To reduce write overhead:
Limit the number of views per base table. Each additional real-time materialized view adds another trigger execution per DML.
Use batch writes. Running
COPYorINSERT INTO SELECTprocesses a large dataset in fewer trigger invocations than row-by-row inserts.Define primary keys on all base tables and include those primary key columns in the view's projection. This allows PolarDB to use unique indexes on the view for faster delta application.
Before deploying real-time materialized views to production, test write performance in a staging environment to confirm the overhead is acceptable for your workload.
Prerequisites
Check your cluster's minor engine version before using real-time materialized views:
SHOW polar_version;V1.1.27 (released September 2022) or later: Real-time materialized views are available by default. No additional setup is needed.
Earlier than V1.1.27: Update the minor engine version to V1.1.27 or later, then install the
polar_ivmextension:CREATE EXTENSION polar_ivm WITH SCHEMA pg_catalog;
Create a real-time materialized view
CREATE MATERIALIZED VIEW table_name [ (column_name [, ...]) ]
[ BUILD DEFERRED | IMMEDIATE ]
REFRESH FAST
ON COMMIT
AS query| Parameter | Description |
|---|---|
table_name | Name of the view. Can be schema-qualified. |
column_name | Column names for the view. If omitted, column names are taken from the query result set. |
BUILD DEFERRED | Creates the view structure without loading data. The view returns no rows until you run REFRESH MATERIALIZED VIEW on it for the first time. |
BUILD IMMEDIATE | Loads data immediately after the view is created. This is the default. |
query | A SELECT, TABLE, or VALUES statement whose results populate the view. Runs in a secure, restricted context. |
Refresh a real-time materialized view
Views created with BUILD IMMEDIATE are updated automatically on every base table DML — no manual refresh is needed.
For views created with BUILD DEFERRED, run the following statement to populate the view for the first time. After this initial refresh, subsequent base table changes are synchronized automatically.
REFRESH MATERIALIZED VIEW table_nameDrop a real-time materialized view
DROP MATERIALIZED VIEW [ IF EXISTS ] table_name [, ...] [ CASCADE | RESTRICT ]| Parameter | Description |
|---|---|
IF EXISTS | Returns a notice instead of an error if the view does not exist. |
table_name | Name of the view to drop. Can be schema-qualified. |
CASCADE | Automatically drops objects that depend on this view (such as other materialized views or regular views), and any objects that depend on those. |
RESTRICT | Refuses to drop the view if any objects depend on it. This is the default. |
End-to-end example
This example creates a real-time materialized view, runs INSERT, DELETE, and UPDATE operations on the base table, and verifies that the view stays synchronized automatically.
Step 1: Install the extension (if needed)
CREATE EXTENSION IF NOT EXISTS polar_ivm WITH SCHEMA pg_catalog;Step 2: Create a base table and load sample data
CREATE TABLE t (a INT, b VARCHAR);
INSERT INTO t VALUES
(1, 'a'),
(2, 'b'),
(3, 'c'),
(4, 'd'),
(5, 'e');Step 3: Create the real-time materialized view
CREATE MATERIALIZED VIEW mv
REFRESH FAST
ON COMMIT
AS
SELECT max(a), min(a), b FROM t GROUP BY b;Step 4: Query the view and verify synchronization
Initial state — matches the base table:
SELECT * FROM mv ORDER BY b; max | min | b
-----+-----+---
1 | 1 | a
2 | 2 | b
3 | 3 | c
4 | 4 | d
5 | 5 | e
(5 rows)After inserting a new row:
INSERT INTO t VALUES (6, 'f');
SELECT * FROM mv ORDER BY b; max | min | b
-----+-----+---
1 | 1 | a
2 | 2 | b
3 | 3 | c
4 | 4 | d
5 | 5 | e
6 | 6 | f
(6 rows)After deleting a row:
DELETE FROM t WHERE a = 2;
SELECT * FROM mv ORDER BY b; max | min | b
-----+-----+---
1 | 1 | a
3 | 3 | c
4 | 4 | d
5 | 5 | e
6 | 6 | f
(5 rows)After updating all rows:
UPDATE t SET a = a + 1;
SELECT * FROM mv ORDER BY b; max | min | b
-----+-----+---
2 | 2 | a
4 | 4 | c
5 | 5 | d
6 | 6 | e
7 | 7 | f
(5 rows)The view reflects each change immediately — no manual refresh needed.
Step 5: Drop the view
DROP MATERIALIZED VIEW mv;