AnalyticDB PostgreSQL版提供了普通物化視圖和實(shí)時物化視圖自動查詢改寫功能,可以大幅提升JOIN、聚合函數(shù)、子查詢、CTE以及高并發(fā)場景下SQL的執(zhí)行性能。

最佳實(shí)踐:使用實(shí)時物化視圖加速帶可變參數(shù)的查詢

功能介紹

早期使用普通物化視圖和實(shí)時物化視圖時,通常需要人工修改查詢SQL,顯式在SQL中指定使用物化視圖。支持自動查詢修改功能后,物化視圖自動查詢改寫功能將自動、透明的重寫查詢SQL,使查詢SQL可以使用物化視圖(即使查詢SQL本身指定的是查詢基表而非物化視圖),從而加速查詢SQL的運(yùn)行。

  • 如果查詢SQL與物化視圖SQL使用的SELECT語句完全相同(全匹配),AnalyticDB PostgreSQL版就會觸發(fā)自動查詢改寫功能,從而使用物化視圖中的數(shù)據(jù)加速查詢。更多關(guān)于全匹配的介紹,請參見全匹配
  • 如果查詢SQL與物化視圖SQL使用的SELECT語句不完全相同,但是物化視圖SQL部分命中查詢SQL的場景,自動查詢改寫會嘗試通過對物化視圖進(jìn)行補(bǔ)償操作完成查詢,具體補(bǔ)償能力的支持,請參見查詢補(bǔ)償

使用限制

  • 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及以上版本。
    說明

開啟或關(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;
說明 該功能暫不支持自助修改實(shí)例級別的配置,如需修改實(shí)例級別配置,請提交工單聯(lián)系技術(shù)支持進(jìn)行修改。

全匹配

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ù)為countsummaxminavg,當(dāng)查詢SQL包含其他聚合函數(shù)時,則不會發(fā)生自動查詢改寫。
    • 當(dāng)查詢SQL包含HAVING子句時,GROUP BY列不支持補(bǔ)償。
  • 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;
    • 支持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;
    • 當(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;
    • 當(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;
  • 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;

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)先級越高。

示例

  • 示例一:
    1. 創(chuàng)建基表。
      CREATE TABLE t1 (a int, b int) DISTRIBUTED BY (a);
    2. 向基表插入測試數(shù)據(jù)。
      INSERT INTO t1 VALUES (generate_series(1, 10), generate_series(1, 2));
    3. 創(chuàng)建物化視圖。
      CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT count(a), b FROM t1 GROUP BY b DISTRIBUTED BY (b);
    4. 執(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)
  • 示例二:
    1. 創(chuàng)建兩張基表。
      CREATE TABLE t1 (a int, b int) DISTRIBUTED BY (a);
      CREATE TABLE t2 (i int, j int) DISTRIBUTED BY (i);
    2. 分別向兩張基表插入測試數(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));
    3. 創(chuàng)建物化視圖。
      CREATE INCREMENTAL MATERIALIZED VIEW mv AS SELECT count(a), a, b FROM t1 GROUP BY a, b DISTRIBUTED BY (a);
    4. 執(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)