Materialized views pre-compute and store query results, so AnalyticDB for MySQL can serve those results directly instead of re-running expensive multi-table joins and aggregations on every query. This topic explains how to create a materialized view, choose a refresh type, and resolve common errors.
Prerequisites
Before you begin, make sure that:
The cluster's kernel version is 3.1.3.4 or later. To check or update the version, go to the Configuration Information section on the Cluster Information page in the AnalyticDB for MySQL console
Your database account has all required permissions:
CREATE permission on tables in the target database
SELECT permission on all columns (or specific columns) of every base table the materialized view references
For automatically refreshed materialized views, additionally:
Permission to connect from
'%'(any IP address)INSERT permission on the materialized view or all tables in its database
Choose a refresh type
AnalyticDB for MySQL supports two refresh types. The refresh type determines which SQL features the query body can use and how the materialized view stays in sync with its base tables.
| Complete refresh | Fast (incremental) refresh | |
|---|---|---|
| How it works | Replaces all data in the materialized view | Applies only the changes since the last refresh |
| Base tables | Internal tables, external tables, existing materialized views, and views | Internal tables only |
| SQL support | Full SELECT syntax | Subset of SELECT (see Incremental MV query constraints) |
| Refresh triggers | Scheduled auto-refresh, auto-refresh on base table overwrite, or manual refresh | Scheduled auto-refresh only (interval: 5 seconds to 5 minutes) |
| Minimum version | 3.1.3.4 | 3.1.9.0 (single-table); 3.2.1.0 (multi-table) |
Prepare base tables
The examples in this topic use the following two tables. Create them before running the materialized view examples.
/*+ RC_DDL_ENGINE_REWRITE_XUANWUV2=false */ -- Set the table engine to XUANWU.
CREATE TABLE customer (
customer_id INT PRIMARY KEY,
customer_name VARCHAR(255),
is_vip Boolean
);
/*+ RC_DDL_ENGINE_REWRITE_XUANWUV2=false */ -- Set the table engine to XUANWU.
CREATE TABLE sales (
sale_id INT PRIMARY KEY,
product_id INT,
customer_id INT,
price DECIMAL(10, 2),
quantity INT,
sale_date TIMESTAMP
);The examples do not specify a resource group. Without a resource group, AnalyticDB for MySQL uses the reserved computing resources of the default interactive resource group to create and refresh materialized views. To use a job resource group instead, see Use elastic resources.
Create a complete-refresh materialized view
Complete-refresh materialized views support the full SELECT syntax and can reference internal tables, external tables, existing materialized views, and views.
The following example creates a materialized view named join_mv that joins customer and sales and is configured for manual refresh:
CREATE MATERIALIZED VIEW join_mv
REFRESH COMPLETE ON DEMAND
AS
SELECT
sale_id,
SUM(price * quantity) AS price
FROM customer
INNER JOIN (SELECT sale_id, customer_id, price, quantity FROM sales) sales
ON customer.customer_id = sales.customer_id
GROUP BY customer.customer_id;To refresh the view manually, run:
REFRESH MATERIALIZED VIEW join_mv;Create a fast (incremental) materialized view
Fast materialized views apply only the changes since the last refresh, which is more efficient for large datasets that change incrementally. The trade-off is a narrower set of supported SQL features — what you write in the SELECT query body determines whether incremental refresh applies (see Incremental MV query constraints).
Version requirement: 3.1.9.0 or later (single-table), 3.2.1.0 or later (multi-table).
Enable binary logging
Incremental refresh relies on binary logging to track changes in base tables. Enable it at the cluster level and for each base table:
SET ADB_CONFIG BINLOG_ENABLE=true;
ALTER TABLE customer binlog=true;
ALTER TABLE sales binlog=true;If enabling binary logging fails, see Can not create FAST materialized view.
Create a single-table fast materialized view
The following example creates a fast materialized view named sales_mv_incre on the sales table with an auto-refresh interval of 3 minutes:
CREATE MATERIALIZED VIEW sales_mv_incre
REFRESH FAST NEXT now() + INTERVAL 3 minute
AS
SELECT
sale_id,
SUM(price * quantity) AS price
FROM sales
GROUP BY sale_id;Create a multi-table fast materialized view
On clusters running V3.2.1.0 or later, fast materialized views can join multiple tables. The following example joins customer and sales:
CREATE MATERIALIZED VIEW join_mv_incre
REFRESH FAST NEXT now() + INTERVAL 3 minute
AS
SELECT
customer.customer_id,
SUM(sales.price) AS price
FROM customer
INNER JOIN (SELECT customer_id, price FROM sales) sales
ON customer.customer_id = sales.customer_id
GROUP BY customer.customer_id;For the complete CREATE MATERIALIZED VIEW syntax, see CREATE MATERIALIZED VIEW.
Monitor creation progress
A CREATE MATERIALIZED VIEW statement can take time because it includes an initial data load. Run the following query to list materialized views currently being created:
SHOW PROCESSLIST WHERE info LIKE '%CREATE MATERIALIZED VIEW%';Each row represents a materialized view in progress. The User field shows the database account, State shows the current status, and Info contains the full CREATE statement. For field definitions, see SHOW PROCESSLIST.
When SHOW PROCESSLIST returns no rows, the materialized view has been created, including its schema and initial data.
Use elastic resources to create or refresh materialized views
By default, AnalyticDB for MySQL uses the reserved computing resources of the default interactive resource group (user_default) to create and refresh materialized views. To avoid contending with interactive workloads, use a job resource group instead.
When to use elastic resources:
You want to isolate materialized view creation and refresh from interactive queries.
You want to avoid purchasing dedicated resources in advance.
Trade-off: Job resource groups provision computing resources on demand, which adds seconds to minutes of startup overhead before each refresh compared to interactive resource groups.
Cluster requirements:
Enterprise Edition, Basic Edition, or Data Lakehouse Edition
V3.1.9.3 or later
Specify a job resource group using MV_PROPERTIES. The following example creates a materialized view using the job resource group my_job_rg at high priority, with daily refresh:
CREATE MATERIALIZED VIEW job_mv
MV_PROPERTIES='{
"mv_resource_group": "my_job_rg",
"mv_refresh_hints": {"query_priority": "HIGH"}
}'
REFRESH COMPLETE ON DEMAND
START WITH now()
NEXT now() + INTERVAL 1 DAY
AS
SELECT * FROM customer;To cap the maximum resources used during refresh, add "elastic_job_max_acu": "<value>" to mv_refresh_hints. For the full list of mv_properties options, see mv_properties.
Refresh trigger mechanisms
A materialized view reflects its data as of the last refresh, not the current state of the base tables. Choose a refresh trigger based on how fresh the data needs to be:
Scheduled auto-refresh: Refreshes at a fixed interval (for example, every 3 minutes, every day). Supported by both complete and fast refresh.
Auto-refresh on base table overwrite: Triggers a refresh when a base table is overwritten. Supported by complete refresh only.
Manual refresh: Run
REFRESH MATERIALIZED VIEW <view_name>;when needed. Supported by complete refresh only.
For details on refresh policies and manual refresh syntax, see Refresh materialized views.
Incremental MV query constraints
The SELECT query body of a fast materialized view has constraints that do not apply to complete-refresh views. The most disqualifying constraint is:
Only INNER JOIN is supported. Join columns must be original columns of the base tables, have identical data types, and be indexed. You can join up to five base tables.
If a constraint prevents your use case, use a complete-refresh materialized view instead — it supports the full SELECT syntax with no join restrictions.
The following table lists all unsupported SQL features.
| Feature | Supported? | Notes |
|---|---|---|
| INNER JOIN (multi-table) | Yes (V3.2.1.0+) | Up to 5 tables; join columns must be indexed and have matching data types |
| UNION ALL | Yes (V3.2.5.0+) | Requires special query structure (see below) |
| COUNT, SUM, MAX, MIN, AVG, APPROX_DISTINCT, COUNT(DISTINCT) | Yes | All other aggregate functions are not supported |
| AVG with DECIMAL | No | Use a different numeric type |
| COUNT(DISTINCT) with non-INTEGER | No | Supports INTEGER type only |
| Window functions | No | — |
| HAVING clause | No | — |
| ORDER BY clause | No | — |
| Nondeterministic expressions (NOW(), RAND()) | No | — |
| UNION, EXCEPT, INTERSECT | No | UNION ALL is supported from V3.2.5.0 |
| XUANWU_V2 tables as base tables | No (before V3.2.6.0) | XUANWU_V2 does not support binary logging |
| Partitioned tables as base tables | No (before V3.2.3.0) | — |
| INSERT OVERWRITE or TRUNCATE on base tables | No (before V3.2.3.1) | Returns an error |
| MAX(), MIN(), APPROX_DISTINCT(), COUNT(DISTINCT) with DELETE/UPDATE/REPLACE/INSERT ON DUPLICATE KEY UPDATE | No | Base tables support INSERT only |
| Fast MV as a base table (nested fast MVs) | Yes (V3.2.5.0+) | Requires binary logging enabled on the materialized view |
To join more than five tables in a fast materialized view, contact technical support.
SELECT column rules
The columns in the SELECT list must follow these rules:
With GROUP BY and aggregate functions: Include all GROUP BY columns in the SELECT list.
With aggregate functions and no GROUP BY: The SELECT list may contain only aggregate columns, or only constant and aggregate columns.
Without aggregation: Include all primary key columns of the base table.
UNION ALL queries: Each branch must output a column named
union_all_markerwith a distinct constant value per branch. Include all base table primary key columns. The materialized view primary key must include both the base table primary key columns andunion_all_marker.CREATE MATERIALIZED VIEW demo_union_all_mv (PRIMARY KEY(id, union_all_marker)) REFRESH FAST NEXT now() + INTERVAL 5 minute AS SELECT customer_id AS id, "customer" AS union_all_marker FROM customer UNION ALL SELECT sale_id AS id, "sales" AS union_all_marker FROM sales;Expression columns: All expression columns in the SELECT list must have aliases, for example
SUM(price) AS total_price.
Limits
General limits
These limits apply to all materialized views.
You cannot run INSERT, DELETE, or UPDATE on a materialized view.
You cannot drop or rename a base table or its columns while a materialized view references them. Drop the materialized view first, then modify the base table.
Maximum materialized views per cluster:
V3.1.4.7 or later: 64
Earlier than V3.1.4.7: 8
To raise the quota, contact technical support.
Limits on complete-refresh materialized views
When you add or remove reserved nodes, asynchronous jobs are disabled. Because complete refresh is an asynchronous job, it cannot run during node scaling. Fast refresh is not affected.
Limits on fast (incremental) materialized views
See Incremental MV query constraints for the full list of SQL restrictions.
Refresh trigger: Only scheduled auto-refresh is supported. The interval must be between 5 seconds and 5 minutes.
Limitations of multi-table joins in incremental materialized views:
Up to five base tables can be joined.
To adjust this limit, to contact technical support based on your cluster specifications.
Only INNER JOIN is supported.
Join columns must be original columns of base tables, have identical data types, and be indexed.
FAQ
How do I keep only the most recent year of data in a materialized view?
Use a date column as the partition key (PARTITION BY) and set a LIFECYCLE value to limit how many partitions are retained. For a view partitioned by day, set LIFECYCLE 365 to keep the most recent 365 partitions (one year).
Example: the sales table receives new records daily, partitioned by sale_date:
CREATE MATERIALIZED VIEW sales_mv_lifecycle
PARTITION BY VALUE(DATE_FORMAT(sale_date, '%Y%m%d')) LIFECYCLE 365
REFRESH FAST NEXT now() + INTERVAL 100 second
AS
SELECT
sale_date,
SUM(price * quantity) AS price
FROM sales
GROUP BY sale_date;Troubleshooting
Query execution error: Can not create FAST materialized view, because *demotable* doesn't support getting incremental data
Binary logging is not enabled for the base table demotable. Enable it with:
ALTER TABLE demotable binlog=true;If you see XUANWU_V2 engine not support ALTER_BINLOG_ENABLE now, the table uses the XUANWU_V2 engine, which does not support binary logging. Because you cannot change a table's engine after creation, you must:
Disable XUANWU_V2 (see options below).
Recreate the table using the XUANWU engine.
Migrate data from the XUANWU_V2 table to the new XUANWU table.
Create the fast materialized view on the XUANWU table.
To disable XUANWU_V2:
For tables created by DTS, zero-ETL, or console data synchronization — disable at the cluster level. All new tables will use XUANWU.
SET adb_config RC_DDL_ENGINE_REWRITE_XUANWUV2=false;For manually created tables — disable at the statement level. Only that specific
CREATE TABLEstatement uses XUANWU; others still use XUANWU_V2./*+ RC_DDL_ENGINE_REWRITE_XUANWUV2=false */ CREATE TABLE ...
Query execution error: PRIMARY KEY *id* must output to MV
Your fast materialized view uses a non-aggregate query without GROUP BY. In this case, the SELECT list must include all primary key columns of the base table.
Incorrect (missing sale_id, which is the primary key of sales):
CREATE MATERIALIZED VIEW wrong_example1
REFRESH FAST ON DEMAND
NEXT now() + interval 200 second
AS
SELECT product_id, price
FROM sales;Add the primary key column:
CREATE MATERIALIZED VIEW correct_example1
REFRESH FAST ON DEMAND
NEXT now() + interval 200 second
AS
SELECT sale_id, product_id, price
FROM sales;Query execution error: MV PRIMARY KEY must be equal to base table PRIMARY KEY
Your fast materialized view uses a non-aggregate query without GROUP BY, and the materialized view primary key definition includes columns that are not part of the base table primary key.
Incorrect (product_id is not a primary key column of sales):
CREATE MATERIALIZED VIEW wrong_example2
(PRIMARY KEY(sale_id, product_id))
REFRESH FAST ON DEMAND
NEXT now() + interval 200 second
AS
SELECT sale_id, product_id, price
FROM sales;Remove non-primary-key columns from the primary key definition:
CREATE MATERIALIZED VIEW correct_example2
(PRIMARY KEY(sale_id))
REFRESH FAST ON DEMAND
NEXT now() + interval 200 second
AS
SELECT sale_id, product_id, price
FROM sales;Query execution error: FAST materialized view must define PRIMARY KEY
This error has two possible causes:
No valid primary key defined. Update the materialized view definition to meet these rules:
Grouped aggregate query (with GROUP BY): the primary key must be the GROUP BY columns (for example, if
GROUP BY a, b, setPRIMARY KEY(a, b)).Non-grouped aggregate query (without GROUP BY): the primary key must be a constant.
Non-aggregate query: the primary key must exactly match the base table primary key (for example, if the base table has
PRIMARY KEY(sale_id, sale_date), the view must also havePRIMARY KEY(sale_id, sale_date)).
A function is applied to a primary key column. Remove the function from the primary key column in the query.
Query execution error: The join graph is not supported
Join columns have mismatched data types. For example, if customer.id and sales.id have different types, the join fails. Align the types with:
ALTER TABLE tablename MODIFY COLUMN columnname newtype;For more information, see Change the data type of a column.
Query execution error: Unable to use index join to refresh this fast MV
Join columns lack indexes. Add an index on each join column:
ALTER TABLE tablename ADD KEY idx_name(columnname);For more information, see Create an index.
Query execution error: Query exceeded reserved memory limit
The query exceeded the per-node memory limit. Use the SQL diagnostics feature to identify high-memory stages and operators (Aggregation, TopN, Window, and Join are the common culprits), then optimize those operators. See also Memory metrics and Use stage and task details to analyze queries.
What's next
Materialized views — concepts, use cases, and feature updates
CREATE MATERIALIZED VIEW — complete syntax reference
Refresh materialized views — refresh policies, triggers, and manual refresh
Manage materialized views — query definitions, refresh history, list, and delete
Query data from a materialized view — query syntax and examples