云原生數據倉庫 AnalyticDB MySQL 版不僅支持查詢物化視圖,還支持查詢改寫,即執行用戶查詢時,自動將查詢改寫成對物化視圖的查詢,提高查詢效率。本文介紹如何使用物化視圖的查詢改寫功能。
前提條件
AnalyticDB for MySQL集群版本為V3.1.4及以上。
說明如何查看集群內核版本,請參見如何查看實例版本信息。如需升級內核版本,請聯系技術支持。
使用物化視圖需要有以下相關權限:
創建視圖需要有數據庫或表級別的CREATE權限。
刷新物化視圖需要有數據庫或表級別的INSERT權限。
需要有物化視圖所涉及的所有表的相關列(或整個表)的SELECT權限。
如果在創建物化視圖時指定物化視圖為自動刷新模式,需要具備通過服務器本地(即
127.0.0.1
)或者任意IP(即'%'
)刷新視圖的權限。
功能介紹
您既可直接查詢物化視圖,也可通過開啟物化視圖的查詢改寫功能,將未使用物化視圖的查詢自動改寫到物化視圖上。此時物化視圖可作為緩存,無需改造查詢SQL也可實現查詢加速。AnalyticDB for MySQL不僅支持改寫與物化視圖結構相同的查詢,還支持通過一系列改寫規則改寫與物化視圖等價的查詢。
查詢改寫方式
AnalyticDB for MySQL會先提取查詢語句的結構信息,判斷查詢語句的結構是否與物化視圖結構一致,并根據判斷結果選擇查詢改寫方式。AnalyticDB for MySQL支持如下改寫方式:
查詢改寫級別
AnalyticDB for MySQL當前僅支持
STALE_TOLERATED
級別的改寫,即使物化視圖中的數據不是最新的,只要可以提高查詢性能,依然可以將用戶查詢改寫成對該物化視圖的查詢。這種方式可以提供最大范圍的查詢改寫,但此數據可能無法反映物化視圖基表的最新數據,可能導致查詢結果不準確。建議您在使用查詢改寫功能前,先刷新物化視圖獲取最新結果后再執行查詢。刷新視圖的方法,請參見全量刷新物化視圖。
使用方法
開啟查詢改寫功能
AnalyticDB for MySQL支持如下開啟方法:
關閉查詢改寫功能
AnalyticDB for MySQL支持如下關閉方法:
通過
ALTER MATERIALIZED VIEW <mv_name> DISABLE QUERY REWRITE;
語句關閉目標物化視圖的查詢改寫功能,詳情請參見管理物化視圖。通過添加Hint來禁止目標查詢使用自動查詢改寫功能,語法如下:
/*+MV_QUERY_REWRITE_ENABLED=false*/
SELECT ...
示例
創建物化視圖時開啟查詢改寫功能,語句如下:
CREATE MATERIALIZED VIEW adb_mv REFRESH START WITH now() + interval 1 day ENABLE QUERY REWRITE AS SELECT course_id,course_name,max(course_grade) AS max_grade FROM tb_courses;
執行查詢,語句如下:
SELECT course_id,course_name,max(course_grade) AS max_grade FROM tb_courses;
通過
EXPLAIN
語句驗證查詢改寫效果,語句如下:EXPLAIN SELECT course_id,course_name,max(course_grade) AS max_grade FROM tb_courses;
返回結果如下:
+---------------+ | Plan Summary | +---------------+ 1- Output[ Query plan ] {Est rowCount: 1.0} 2 -> Exchange[GATHER] {Est rowCount: 1.0} 3 - TableScan {table: adb_mv, Est rowCount: 1.0}
從上述執行計劃可以看出,查詢時實際使用的是存儲在物化視圖
adb_mv
中的數據,而不是tb_courses
表中的數據。
使用限制
物化視圖中存在不支持改寫的內容,改寫功能會失效。
AnalyticDB for MySQL支持完全匹配改寫和高級查詢改寫兩種方式,兩種方式的使用限制不同,其中:
當物化視圖中存在如下內容時,完全匹配改寫會失效:
非確定性函數(Non-Deterministic Functions),例如
now
,current_timestamp
,random
等函數。用戶自定義函數(User-defined Functions)。
當物化視圖存在如下內容時,高級查詢改寫會失效:
Order By、Limit、或Offset語句。
Union或Union All語句。
Group By語句中出現Grouping Sets、Cube或Rollup。
Window Functions。
Full Outer Join。
系統表。
關聯子查詢。
非確定性函數(Non-Deterministic Functions),例如
now
,current_timestamp
,random
等函數。用戶定義函數(User-defined Functions)。
Having語句。
Self Join(同一個表重復出現)。
若涉及的查詢存在于如下語句中,查詢改寫功能會失效。
CREATE TABLE AS SELECT。
INSERT INTO SELECT。
INSERT OVERWRITE SELECT。
REPLACE INTO SELECT。
DELETE或UPDATE。
其它情況。
若查詢語句沒有設置過濾條件或聚合函數的單表查詢,查詢改寫功能會失效。
改寫范圍
改寫范圍示例中都使用了相同的表,表創建語句如下:
CREATE TABLE part (
partkey INTEGER NOT NULL,
name VARCHAR(55) NOT NULL,
type VARCHAR(25) NOT NULL
);
CREATE TABLE lineitem (
orderkey BIGINT,
partkey BIGINT NOT NULL,
suppkey BIGINT NOT NULL,
extendedprice DOUBLE NOT NULL,
discount DOUBLE NOT NULL,
returnflag CHAR(1) NOT NULL,
linestatus CHAR(1) NOT NULL,
shipdate DATE NOT NULL,
shipmode VARCHAR(25) NOT NULL,
commitdate DATE NOT NULL,
receiptdate DATE NOT NULL
);
CREATE TABLE orders (
orderkey BIGINT PRIMARY KEY,
custkey BIGINT NOT NULL,
orderstatus VARCHAR(1) NOT NULL,
totalprice DOUBLE NOT NULL,
orderdate DATE NOT NULL
);
CREATE TABLE partsupp (
partkey INTEGER NOT NULL PRIMARY KEY,
suppkey INTEGER NOT NULL,
availqty INTEGER NOT NULL,
supplycost DECIMAL(15,2) NOT NULL
);
完全匹配改寫
AnalyticDB for MySQL會提取查詢語句的結構信息,若查詢語句的結構和物化視圖的結構完全相同,AnalyticDB for MySQL會直接將查詢改寫為對物化視圖的查詢。
示例
原查詢語句如下:
SELECT l.returnflag, l.linestatus, SUM(l.extendedprice * (1 - l.discount)), COUNT(*) AS count_order FROM lineitem AS l GROUP BY l.returnflag, l.linestatus;
物化視圖語句如下:
CREATE MATERIALIZED VIEW mv0 REFRESH NEXT now() + interval 1 day ENABLE QUERY REWRITE AS SELECT l.returnflag, l.linestatus, SUM (l.extendedprice * (1 - l.discount)) AS sum_disc_price, count(*) AS count_order FROM lineitem AS l GROUP BY l.returnflag, l.linestatus;
開啟物化視圖改寫功能后,若再次執行原查詢,原語句會被改寫為如下語句進行查詢:
SELECT returnflag, linestatus, sum_disc_price, count_order FROM mv0;
高級查詢改寫
若查詢語句的結構和物化視圖的結構不同,AnalyticDB for MySQL會運用一系列改寫規則,來依次檢查物化視圖和查詢中的Filter
、Join
、Aggregation
和 Group By
表達式,嘗試用物化視圖構建一個等價的查詢表達式,來回答原始查詢或查詢中的某一部分。
高級查詢改寫支持如下改寫規則:
Filter
當查詢的謂詞和物化視圖的謂詞不同時,AnalyticDB for MySQL會使用Filter改寫規則來構造補償表達式。若查詢中出現的表達式不存在于視圖中,系統也會嘗試從視圖中計算該表達式。示例如下:
原查詢語句如下:
SELECT l.shipmode, l.extendedprice * (1 - l.discount) AS disc_price FROM orders AS o, lineitem AS l WHERE o.orderkey = l.orderkey AND l.shipmode in ('REG AIR', 'TRUCK') AND l.commitdate < l.receiptdate AND l.shipdate < l.commitdate;
物化視圖創建語句如下:
CREATE MATERIALIZED VIEW mv1 REFRESH NEXT now() + interval 1 day ENABLE QUERY REWRITE AS SELECT l.shipmode, l.extendedprice, l.discount FROM orders AS o, lineitem AS l WHERE o.orderkey = l.orderkey AND l.commitdate < l.receiptdate AND l.shipdate < l.commitdate;
開啟物化視圖改寫功能后,若再次執行原查詢,原語句即會被改寫為如下語句進行查詢:
SELECT shipmode, extendedprice * (1 - discount) AS disc_price, discount FROM mv1 WHERE shipmode in ('REG AIR', 'TRUCK');
Join
AnalyticDB for MySQL支持在查詢和物化視圖中使用Inner Join和Outer Join,且支持包括Left Join、Right Join在內的任意Join順序。當目標查詢和物化視圖中包含的Join關系不同時,AnalyticDB for MySQL會嘗試通過Join規則,在物化視圖的基礎上計算出目標查詢所需的Join關系。例如,AnalyticDB for MySQL會過濾物化視圖中的某行數據,使得帶Outer Join的物化視圖可以用來計算帶有Inner Join關系的查詢。示例如下:
原查詢語句如下:
SELECT p.type, p.partkey, ps.suppkey FROM part AS p, partsupp AS ps WHERE p.partkey = ps.partkey AND p.type NOT LIKE 'MEDIUM POLISHED%';
物化視圖創建語句如下:
CREATE MATERIALIZED VIEW mv2 REFRESH NEXT now() + INTERVAL 1 day ENABLE QUERY REWRITE AS SELECT p.type, p.partkey, ps.suppkey FROM partsupp AS ps INNER JOIN part AS p ON p.partkey = ps.partkey WHERE p.type NOT LIKE 'MEDIUM POLISHED%';
開啟物化視圖改寫功能后,若再次執行原查詢,原語句即會被改寫為如下語句進行查詢:
SELECT type, partkey, suppkey FROM mv2;
Aggregation
若目標查詢或物化視圖中使用了不同的GROUP BY或聚合函數,AnalyticDB for MySQL會通過
Aggregation
規則,從物化視圖中構造出相同的聚合函數。示例如下:原查詢語句如下:
SELECT l.returnflag, l.linestatus, SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price FROM lineitem AS l GROUP BY l.returnflag, l.linestatus;
物化視圖創建語句如下:
CREATE MATERIALIZED VIEW mv3 REFRESH NEXT now() + INTERVAL 1 day ENABLE QUERY REWRITE AS SELECT l.returnflag, l.linestatus, SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price, COUNT(*) AS count_order FROM lineitem AS l GROUP BY l.returnflag, l.linestatus;
開啟物化視圖改寫功能后,若再次執行原查詢,原語句即會被改寫為如下語句進行查詢:
SELECT returnflag, linestatus, sum_disc_price, count_order FROM mv3;
Aggregation Rollup
若目標查詢和物化視圖中Group By的列表不同,AnalyticDB for MySQL會嘗試通過
Rollup
規則,對物化視圖進行Rollup。示例如下:原查詢語句如下:
SELECT l.returnflag, SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price, COUNT(*) AS count_order FROM lineitem AS l WHERE l.returnflag = 'R' GROUP BY l.returnflag;
物化視圖創建語句如下:
CREATE MATERIALIZED VIEW mv4 REFRESH NEXT now() + INTERVAL 1 day ENABLE QUERY REWRITE AS SELECT l.returnflag, l.linestatus, SUM(l.extendedprice * (1 - l.discount)) AS sum_disc_price, COUNT(*) AS count_order FROM lineitem AS l GROUP BY l.returnflag, l.linestatus;
開啟物化視圖改寫功能后,若再次執行原查詢,原語句即會被改寫為如下語句進行查詢:
SELECT returnflag, linestatus, sum_disc_price, count_order FROM mv4 WHERE returnflag = 'R' GROUP BY returnflag;
Subqueries
若目標查詢和物化視圖的子查詢不同,AnalyticDB for MySQL會嘗試使用
Subqueries
規則進行查詢改寫。示例如下:原查詢語句如下:
SELECT p.type, p.partkey, ps.suppkey FROM part AS p, (SELECT * FROM partsupp WHERE suppkey > 10) ps WHERE p.partkey = ps.partkey;
物化視圖創建語句如下:
CREATE MATERIALIZED VIEW mv5 REFRESH NEXT now() + INTERVAL 1 day ENABLE QUERY REWRITE AS SELECT p.type, p.partkey, ps.suppkey FROM part AS p, partsupp AS ps WHERE p.partkey = ps.partkey;
開啟物化視圖改寫功能后,若再次執行原查詢,原語句即會被改寫為如下語句進行查詢:
SELECT type, partkey, suppkey FROM mv5 WHERE suppkey > 10;
Query Partial
若目標查詢中涉及的表不在物化視圖中,AnalyticDB for MySQL會通過
Query Partial
規則嘗試為物化視圖的結果加入缺失的表。示例如下:原查詢語句如下:
SELECT p.type, p.partkey, ps.suppkey FROM part AS p, partsupp AS ps WHERE p.partkey = ps.partkey AND p.type NOT LIKE 'MEDIUM POLISHED%';
物化視圖創建語句如下:
CREATE MATERIALIZED VIEW mv6 REFRESH NEXT now() + INTERVAL 1 day ENABLE QUERY REWRITE AS SELECT p.type, p.partkey FROM part AS p WHERE p.type NOT LIKE 'MEDIUM POLISHED%';
開啟物化視圖改寫功能后,若再次執行原查詢,原語句即會被改寫為如下語句進行查詢:
CREATE MATERIALIZED VIEW mv6 REFRESH NEXT now() + INTERVAL 1 day ENABLE QUERY REWRITE AS SELECT p.type, p.partkey FROM part AS p WHERE p.type NOT LIKE 'MEDIUM POLISHED%';
Union
如果物化視圖僅包含一部分數據,AnalyticDB for MySQL會使用
Union
改寫規則,即先使用物化視圖中已有的數據進行計算獲得部分查詢結果,剩下的查詢結果從基表中計算得到。原查詢語句如下:
SELECT l.linestatus, COUNT(*) AS count_order FROM lineitem AS l WHERE l.shipdate >= DATE '1998-01-01' GROUP BY l.linestatus;
物化視圖創建語句如下:
CREATE MATERIALIZED VIEW mv7 REFRESH NEXT now() + interval 1 day ENABLE QUERY REWRITE AS SELECT l.linestatus, COUNT(*) AS count_order FROM lineitem AS l WHERE l.shipdate >= DATE '2000-01-01' GROUP BY l.linestatus;
開啟物化視圖改寫功能后,若再次執行原查詢,原語句即會被改寫為如下語句進行查詢:
SELECT linestatus, count_order FROM ( SELECT linestatus, count_order FROM mv7 UNION ALL SELECT l.linestatus, COUNT(*) AS count_order FROM lineitem AS l WHERE l.shipdate >= DATE '1998-01-01' AND l.shipdate < DATE '1998-01-01' GROUP BY l.linestatus) GROUP BY linestatus;
常見問題
Q:物化視圖創建后,為什么自動改寫沒有生效?