AnalyticDB PostgreSQL版提供了普通物化視圖和實(shí)時物化視圖自動查詢改寫功能,可以大幅提升JOIN、聚合函數(shù)、子查詢、CTE以及高并發(fā)場景下SQL的執(zhí)行性能。
最佳實(shí)踐:使用實(shí)時物化視圖加速帶可變參數(shù)的查詢
功能介紹
早期使用普通物化視圖和實(shí)時物化視圖時,通常需要人工修改查詢SQL,顯式在SQL中指定使用物化視圖。支持自動查詢修改功能后,物化視圖自動查詢改寫功能將自動、透明的重寫查詢SQL,使查詢SQL可以使用物化視圖(即使查詢SQL本身指定的是查詢基表而非物化視圖),從而加速查詢SQL的運(yùn)行。
使用限制
- SELECT FOR UPDATE語句不會參與自動查詢改寫。
- 包含遞歸CTE的語句不會參與自動查詢改寫。
- 包含隨機(jī)函數(shù)的查詢(例如
random()
,now()
等)不會參與自動查詢改寫。 - 當(dāng)查詢SQL與物化視圖SQL不完全相同,且不在本文中說明的查詢補(bǔ)償支持的情況范圍內(nèi)的場景,不支持自動查詢改寫。關(guān)于查詢補(bǔ)償相關(guān)信息,請參見查詢補(bǔ)償。
- 內(nèi)核小版本為V6.3.6.0及以上版本。
說明
- 查看實(shí)例的內(nèi)核版本,請參見查看內(nèi)核小版本。
- 升級實(shí)例的內(nèi)核版本,請參見版本升級。
開啟或關(guān)閉自動查詢改寫
- 實(shí)時物化視圖
默認(rèn)情況下,實(shí)時物化視圖的自動查詢改寫功能為開啟狀態(tài),您可以通過以下命令關(guān)閉該功能。
SET enable_incremental_matview_query_rewrite TO off;
- 普通物化視圖
默認(rèn)情況下,普通物化視圖的自動查詢改寫功能為關(guān)閉狀態(tài),您可以通過以下命令開啟該功能。
SET enable_matview_query_rewrite TO on;
全匹配
AnalyticDB PostgreSQL版自動查詢改寫是基于語法樹的匹配。全匹配會自動忽略空格、換行、注釋、別名等影響。只要查詢SQL和物化視圖SQL在語法層面完全相同,就會優(yōu)先使用物化視圖,從而加速查詢。
查詢補(bǔ)償
AnalyticDB PostgreSQL版自動查詢改寫支持查詢SQL與物化視圖SQL不完全相同的場景。這種場景下,自動查詢改寫會嘗試改寫查詢SQL,補(bǔ)償物化視圖SQL和查詢SQL之間缺少的計算動作,并返回最終結(jié)果以保證查詢的正確性。
目前查詢SQL中僅SELECT列、JOIN表、GROUP BY列、WHERE子句、HAVING子句、ORDER BY列、LIMIT子句支持查詢補(bǔ)償,除了上述部分,SQL中其它部分需要和物化視圖SQL完全相同,否則不會發(fā)生自動查詢改寫。
- SELECT列
當(dāng)SQL查詢的SELECT列與物化視圖SQL的SELECT列不完全相同時,自動查詢改寫對SELECT列支持情況如下:
- 支持查詢SQL的SELECT列的順序與物化視圖SQL不同。
- 支持物化視圖SQL中的SELECT列沒有出現(xiàn)在查詢SQL中。
- 支持查詢SQL中的SELECT列不在物化視圖SQL的SELECT列中,但是可以由物化視圖SQL的SELECT列組合計算得到。
- 不支持查詢SQL中的SELECT列不在物化視圖SQL的SELECT列中,且無法由物化視圖SQL的SELECT列組合計算得到。
- GROUP BY列
當(dāng)SQL查詢的GROUP BY列與物化視圖SQL不完全相同時,自動查詢改寫對GROUP BY列的支持情況如下:
- 如果物化視圖SQL不包含GROUP BY和聚合函數(shù):
- 支持查詢SQL包含聚合函數(shù)。
- 支持查詢SQL包含GROUP BY。
- 支持查詢SQL包含GROUP BY和聚合函數(shù)。
- 如果物化視圖SQL包含GROUP BY但是不包含聚合函數(shù):
- 支持物化視圖SQL的GROUP BY列不在查詢SQL中。
- 不支持查詢SQL的GROUP BY列不在物化視圖SQL中。
- 查詢SQL僅支持
count(distinct)
聚合函數(shù),其他聚合函數(shù)均不支持。
- 如果物化視圖SQL不包含GROUP BY但是包含聚合函數(shù):
- 不支持查詢SQL包含GROUP BY列。
- 如果物化視圖SQL包含GROUP BY列和聚合函數(shù):
- 支持物化視圖SQL的GROUP BY列不在查詢SQL中。
- 不支持查詢SQL的GROUP BY列不在物化視圖SQL中。
說明- 當(dāng)查詢SQL的GROUP BY列比物化視圖SQL少時,自動查詢改寫需要對聚合函數(shù)進(jìn)行重聚和補(bǔ)償,重聚和支持的聚合函數(shù)為
count
、sum
、max
、min
、avg
,當(dāng)查詢SQL包含其他聚合函數(shù)時,則不會發(fā)生自動查詢改寫。 - 當(dāng)查詢SQL包含HAVING子句時,GROUP BY列不支持補(bǔ)償。
- 如果物化視圖SQL不包含GROUP BY和聚合函數(shù):
- JOIN表
當(dāng)查詢SQL的JOIN表或JOIN條件與物化視圖SQL不完全相同時,自動查詢改寫對JOIN表的支持情況如下:
- 對于INNER JOIN,支持表交換順序,支持補(bǔ)償額外的JOIN表與補(bǔ)償額外的JOIN條件。
- 對于OUTER JOIN,支持LEFT JOIN與RIGHT JOIN互相轉(zhuǎn)換,支持FULL JOIN的左右表交換,不支持補(bǔ)償額外的表與JOIN條件。
當(dāng)查詢SQL的JOIN表與物化視圖SQL相同時:
- 支持INNER JOIN表的順序交換,示例如下:
- 物化視圖SQL的SELECT部分如下:
SELECT * FROM a, b WHERE a.i = b.i;
可以被自動查詢改寫的查詢SQL如下:
SELECT * FROM b, a WHERE a.i = b.i; SELECT * FROM a INNER JOIN b ON a.i = b.i;
- 物化視圖SQL的SELECT部分如下:
SELECT * FROM a INNER JOIN b ON a.i = b.i;
可以被自動查詢改寫的查詢SQL如下:
SELECT * FROM b INNER JOIN a ON a.i = b.i;
- 物化視圖SQL的SELECT部分如下:
- 支持LEFT JOIN與RIGHT JOIN互相轉(zhuǎn)換,示例如下:
物化視圖SQL的SELECT部分如下:
SELECT * FROM a LEFT JOIN b ON a.i = b.i;
可以被自動查詢改寫的查詢SQL如下:
SELECT * FROM b RIGHT JOIN a ON b.i = a.i;
- 支持FULL OUTER JOIN表左右順序交換,示例如下:
物化視圖SQL的SELECT部分如下:
SELECT * FROM a FULL OUTER JOIN b ON a.i = b.i;
可以被自動查詢改寫的查詢SQL如下:
SELECT * FROM b FULL OUTER JOIN a ON b.i = a.i;
當(dāng)查詢SQL的JOIN表與物化視圖SQL不完全相同時:
支持補(bǔ)償額外的INNER JOIN表。此時支持INNER JOIN與COMMON JOIN表的順序交換,以及兩者之間的轉(zhuǎn)換。示例如下:
- 物化視圖SQL的SELECT部分如下:
SELECT * FROM a, b;
可以被自動查詢改寫的查詢SQL如下:
SELECT * FROM a, b, c;
- 物化視圖SQL的SELECT部分如下:
SELECT * FROM a INNER JOIN b ON a.i = b.i;
可以被自動查詢改寫的查詢SQL如下:
SELECT * FROM a INNER JOIN b ON a.i = b.i INNER JOIN c ON a.i = c.i;
- WHERE子句
當(dāng)查詢SQL的WHERE子句與物化視圖SQL不完全相同時,自動查詢改寫對WHERE子句支持情況如下:
- 當(dāng)查詢SQL和物化視圖SQL的WHERE都是由AND連接多個條件時:
- 支持查詢SQL的WHERE的多個條件的順序與物化視圖SQL的不同,示例如下:
物化視圖SQL的SELECT部分如下:
SELECT * FROM t WHERE a > 100 AND a < 200;
可以被自動查詢改寫的查詢SQL如下:
SELECT * FROM t WHERE a < 200 AND a > 100;
- 支持查詢SQL的WHERE子句沒有出現(xiàn)在物化視圖SQL的WHERE子句中,該場景自動查詢改寫會對物化視圖中缺少的WHERE子句進(jìn)行補(bǔ)償,但是需要補(bǔ)償?shù)腤HERE子句所涉及的列必須在物化視圖中存在。示例如下:
物化視圖SQL的SELECT部分如下:
SELECT * FROM t WHERE a > 100;
可以被自動查詢改寫的查詢SQL如下:
SELECT * FROM t WHERE b > 200 AND a > 100;
- 支持查詢SQL的WHERE的多個條件的順序與物化視圖SQL的不同,示例如下:
- 當(dāng)查詢SQL和物化視圖SQL的WHERE都是由OR連接多個條件時:
- 支持查詢SQL的WHERE的多個條件的順序與物化視圖SQL不同,但是查詢SQL中所有WHERE子句涉及的列都必須在物化視圖中存在。示例如下:
物化視圖SQL的SELECT部分如下:
SELECT * FROM t WHERE a > 100 OR a < 200;
可以被自動查詢改寫的查詢SQL如下:
SELECT * FROM t WHERE a < 200 OR a > 100;
- 支持物化視圖SQL的WHERE子句沒有出現(xiàn)在查詢SQL的WHERE子句中,但是查詢SQL中所有WHERE子句涉及的列都必須在物化視圖中存在。示例如下:
物化視圖SQL的SELECT部分如下:
SELECT * FROM t WHERE a > 100 OR a < 200;
可以被自動查詢改寫的查詢SQL如下:
SELECT * FROM t WHERE a < 200;
- 支持查詢SQL的WHERE的多個條件的順序與物化視圖SQL不同,但是查詢SQL中所有WHERE子句涉及的列都必須在物化視圖中存在。示例如下:
- 當(dāng)物化視圖SQL的WHERE子句包含查詢SQL的WHERE子句時:
- 支持查詢SQL的WHERE子句為等值,而物化視圖SQL的WHERE子句為范圍,但是查詢SQL中所有WHERE子句涉及的列都必須在物化視圖中存在。示例如下:
物化視圖SQL的SELECT部分如下:
SELECT * FROM t WHERE a < 200 AND a >= 100;
可以被自動查詢改寫的查詢SQL如下:
SELECT * FROM t WHERE a = 102;
- 支持查詢SQL的WHERE子句和物化視圖SQL的WHERE子句均為限制范圍,但是查詢SQL中所有WHERE子句涉及的列都必須在物化視圖中存在。示例如下:
物化視圖SQL的SELECT部分如下:
SELECT * FROM t WHERE a < 200 AND a >= 0;
可以被自動查詢改寫的查詢SQL如下:
SELECT * FROM t WHERE a <= 100 AND a > 50;
- 支持查詢SQL的WHERE子句為等值,而物化視圖SQL的WHERE子句為范圍,但是查詢SQL中所有WHERE子句涉及的列都必須在物化視圖中存在。示例如下:
- 當(dāng)查詢SQL和物化視圖SQL的WHERE都是由AND連接多個條件時:
- HAVING子句當(dāng)查詢SQL的HAVING子句與物化視圖SQL不完全相同時,自動查詢改寫對HAVING子句支持情況如下:
- 當(dāng)GROUP BY列不需要補(bǔ)償?shù)那闆r下,自動查詢改寫對HAVING子句的補(bǔ)償方式與WHERE子句的補(bǔ)償方式類似,支持對物化視圖缺少的AND條件進(jìn)行補(bǔ)償;支持對物化視圖多余的OR條件進(jìn)行裁剪;支持對物化視圖的范圍條件進(jìn)一步縮小。
- 當(dāng)GROUP BY列需要補(bǔ)償?shù)那闆r下,僅支持查詢SQL包含HAVING而物化視圖SQL中不包含HAVING的改寫。
- ORDER BY列
無論物化視圖SQL中是否包含ORDER BY,自動查詢改寫都會嘗試進(jìn)行ORDER BY補(bǔ)償。所以查詢SQL的ORDER BY列必須在物化視圖SQL的SELECT列中,否則自動查詢改寫不會發(fā)生。
- LIMIT子句
當(dāng)物化視圖SQL中不包含LIMIT子句時,自動查詢改寫會進(jìn)行LIMIT補(bǔ)償。如果物化視圖SQL中包含LIMIT子句,那么查詢SQL必須與物化視圖SQL完全一致。
- 表達(dá)式補(bǔ)償
對于查詢SQL中的普通表達(dá)式和聚合函數(shù)表達(dá)式,如果整個表達(dá)式無法與物化視圖SQL中的表達(dá)式直接匹配,則會嘗試使用它的子表達(dá)式來查找匹配項(xiàng)。子表達(dá)式按自上而下的順序進(jìn)行嘗試以獲得最大的表達(dá)式匹配。示例如下:
物化視圖SQL的SELECT部分如下:
SELECT a+b, c FROM t;
可以被自動查詢改寫的查詢SQL如下:
SELECT a+b, (a+b)+c, mod(a+b, c) FROM t; SELECT sum((a+b)*c) FROM t;
自動查詢改寫對聚合函數(shù)表達(dá)式支持情況如下:
- 支持通過物化視圖SQL的
sum()
和count()
聚合函數(shù),計算出avg()
聚合函數(shù)。 - 支持查詢SQL和物化視圖SQL間
count(*)
和count(1)
的互換匹配。
聚合函數(shù)表達(dá)式示例如下:
物化視圖SQL的SELECT部分如下:
SELECT sum(a), count(a), count(*) FROM t;
可以被自動查詢改寫的查詢SQL如下:
SELECT avg(a), count(1) FROM;
- 支持通過物化視圖SQL的
CTE和子查詢
自動查詢改寫處理CTE和子查詢的方式類似,都是分為主查詢和子查詢來處理(CTE的WITH中的查詢類似于子查詢)。
- 當(dāng)查詢SQL僅包含一個子查詢時:
- 若查詢SQL與物化視圖SQL的主查詢以及子查詢完全相同,進(jìn)行全匹配替換。
- 若查詢SQL與物化視圖SQL的子查詢完全相同,但是查詢的主查詢需要進(jìn)行查詢補(bǔ)償,關(guān)于查詢補(bǔ)償,請參見查詢補(bǔ)償。
- 若查詢SQL包含子查詢,而物化視圖SQL不包含子查詢:
- 物化視圖SQL與查詢SQL的父查詢相同或可以補(bǔ)償,支持對物化視圖補(bǔ)償一個子查詢來返回查詢。需要注意,不支持補(bǔ)償關(guān)聯(lián)子查詢。
- 物化視圖SQL與查詢SQL的子查詢相同或可以補(bǔ)償,支持僅替換查詢中的子查詢。
- 如果查詢SQL的主查詢或者子查詢被一個物化視圖替換后,自動查詢改寫還會繼續(xù)嘗試對剩余的部分進(jìn)行替換。
- 當(dāng)前物化視圖自動查詢改寫暫時不支持遞歸CTE(WITH RECURSIVE)的語句的替換。
- 當(dāng)查詢SQL包含多個子查詢時:
如果查詢的主查詢或某一個子查詢被改寫后,自動查詢改寫還會繼續(xù)重復(fù)上述規(guī)則,嘗試對剩余部分進(jìn)行改寫。
UNION、EXCEPT、INTERSECT
- 如果查詢SQL與物化視圖SQL都包含UNION、EXCEPT、INTERSECT,UNION、INTERSECT支持UNION、INTERSECT子句的順序交換,以及額外補(bǔ)償U(kuò)NION、INTERSECT子句;EXCEPT僅支持額外補(bǔ)償子句,不能進(jìn)行順序交換。
- 如果查詢SQL包含UNION、EXCEPT、INTERSECT,而物化視圖SQL不包含UNION、EXCEPT、INTERSECT,自動查詢改寫支持通過補(bǔ)償U(kuò)NION、EXCEPT、INTERSECT將多個物化視圖作為UNION、EXCEPT、INTERSECT的子句連接起來。
匹配多個物化視圖
如果一個查詢SQL,有多個物化視圖可以與之匹配,自動查詢改寫會按如下優(yōu)先級選擇物化視圖:
- 優(yōu)先全匹配,當(dāng)不存在全匹配的物化視圖時才會嘗試選擇需要進(jìn)行補(bǔ)償?shù)奈锘晥D。
- 當(dāng)有多個需要進(jìn)行補(bǔ)償?shù)奈锘晥D時,查詢SQL涉及的表與物化視圖涉及的表匹配的數(shù)量越多,優(yōu)先級越高。
- 當(dāng)有多個需要進(jìn)行補(bǔ)償?shù)奈锘晥D與查詢SQL涉及的表匹配數(shù)量相同時,根據(jù)物化視圖的數(shù)據(jù)存儲大小作為優(yōu)先級標(biāo)準(zhǔn),物化視圖的數(shù)據(jù)存儲大小越小,優(yōu)先級越高。
示例
- 示例一:
- 創(chuàng)建基表。
CREATE TABLE t1 (a int, b int) DISTRIBUTED BY (a);
- 向基表插入測試數(shù)據(jù)。
INSERT INTO t1 VALUES (generate_series(1, 10), generate_series(1, 2));
- 創(chuàng)建物化視圖。
CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT count(a), b FROM t1 GROUP BY b DISTRIBUTED BY (b);
- 執(zhí)行查詢計劃。
EXPLAIN SELECT count(a), b FROM t1 GROUP BY b;
返回信息如下,自動查詢改寫進(jìn)行了全匹配替換返回了視圖mv的數(shù)據(jù)。
QUERY PLAN ----------------------------------------------------------------------------- Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..2.02 rows=2 width=12) -> Seq Scan on mv (cost=0.00..2.02 rows=1 width=12) Optimizer: Postgres query optimizer (3 rows)
- 創(chuàng)建基表。
- 示例二:
- 創(chuàng)建兩張基表。
CREATE TABLE t1 (a int, b int) DISTRIBUTED BY (a); CREATE TABLE t2 (i int, j int) DISTRIBUTED BY (i);
- 分別向兩張基表插入測試數(shù)據(jù)。
INSERT INTO t1 VALUES (generate_series(1, 10), generate_series(1, 2)); INSERT INTO t2 VALUES (generate_series(1, 10), generate_series(1, 2));
- 創(chuàng)建物化視圖。
CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT count(a), a, b FROM t1 GROUP BY a, b DISTRIBUTED BY (a);
- 執(zhí)行查詢計劃。
EXPLAIN SELECT count(a) FROM t1 JOIN t2 ON t1.a = t2.i WHERE b > 3 GROUP BY a;
返回信息如下,自動查詢改寫補(bǔ)償了JOIN表、WHERE子句并裁剪了GROUP BY列返回了視圖mv的數(shù)據(jù)。
QUERY PLAN ---------------------------------------------------------------------------------- ---------------- Gather Motion 3:1 (slice1; segments: 3) (cost=0.00..437.00 rows=1 width=8) -> Result (cost=0.00..437.00 rows=1 width=8) -> GroupAggregate (cost=0.00..437.00 rows=1 width=8) Group Key: mv.a -> Sort (cost=0.00..437.00 rows=1 width=12) Sort Key: mv.a -> Hash Join (cost=0.00..437.00 rows=1 width=12) Hash Cond: (mv.a = t2.i) -> Index Scan using mv_index on mv (cost=0.00..6.00 r ows=1 width=12) Index Cond: (b > 3) -> Hash (cost=431.00..431.00 rows=4 width=4) -> Seq Scan on t2 (cost=0.00..431.00 rows=4 wid th=4) Optimizer: Pivotal Optimizer (GPORCA) version 3.86.0 (13 rows)
- 創(chuàng)建兩張基表。