文件首頁
MySQL 8.4 參考手冊
相關文件 下載本手冊
PDF (US Ltr) - 39.9Mb
PDF (A4) - 40.0Mb
Man Pages (TGZ) - 258.5Kb
Man Pages (Zip) - 365.5Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 8.4 參考手冊  /  ...  /  使用合併或實體化最佳化衍生表、視圖參考和通用表表達式

10.2.2.4 使用合併或實體化最佳化衍生表、視圖參考和通用表表達式

最佳化工具可以使用兩種策略處理衍生表參考(這也適用於視圖參考和通用表表達式)

  • 將衍生表合併到外部查詢區塊中

  • 將衍生表實體化為內部暫存資料表

範例 1

SELECT * FROM (SELECT * FROM t1) AS derived_t1;

透過合併衍生表 derived_t1,該查詢的執行方式類似於

SELECT * FROM t1;

範例 2

SELECT *
  FROM t1 JOIN (SELECT t2.f1 FROM t2) AS derived_t2 ON t1.f2=derived_t2.f1
  WHERE t1.f1 > 0;

透過合併衍生表 derived_t2,該查詢的執行方式類似於

SELECT t1.*, t2.f1
  FROM t1 JOIN t2 ON t1.f2=t2.f1
  WHERE t1.f1 > 0;

透過實體化,derived_t1derived_t2 在各自的查詢中都會被視為個別資料表。

最佳化工具會以相同方式處理衍生表、視圖參考和通用表表達式:它會盡可能避免不必要的實體化,這可以將條件從外部查詢向下推送到衍生表,並產生更有效率的執行計畫。(如需範例,請參閱章節 10.2.2.2,「使用實體化最佳化子查詢」。)

如果合併會導致外部查詢區塊參考超過 61 個基本資料表,最佳化工具會改為選擇實體化。

如果下列條件皆為真,最佳化工具會將衍生表或視圖參考中的 ORDER BY 子句傳播到外部查詢區塊

  • 外部查詢未群組或彙總。

  • 外部查詢未指定 DISTINCTHAVINGORDER BY

  • 外部查詢在 FROM 子句中只有此衍生表或視圖參考作為來源。

否則,最佳化工具會忽略 ORDER BY 子句。

下列方法可用於影響最佳化工具是否嘗試將衍生表、視圖參考和通用表表達式合併到外部查詢區塊中

  • 可以使用 MERGENO_MERGE 最佳化工具提示。它們的應用前提是沒有其他規則阻止合併。請參閱章節 10.9.3,「最佳化工具提示」

  • 同樣地,您可以使用 optimizer_switch 系統變數的 derived_merge 旗標。請參閱章節 10.9.2,「可切換最佳化」。依預設,會啟用該旗標以允許合併。停用該旗標會阻止合併並避免 ER_UPDATE_TABLE_USED 錯誤。

    derived_merge 旗標也適用於未包含 ALGORITHM 子句的視圖。因此,如果在使用相當於子查詢的表達式的視圖參考中發生 ER_UPDATE_TABLE_USED 錯誤,則將 ALGORITHM=TEMPTABLE 新增至視圖定義會阻止合併,並優先於 derived_merge 值。

  • 雖然在子查詢中使用任何會阻止合併的結構,就能夠停用合併,但這些結構對實體化的影響並不明顯。會阻止合併的結構對於衍生表、通用表表達式和視圖參考是相同的。

    • 聚合函數或視窗函數(SUM()MIN()MAX()COUNT() 等等)

    • DISTINCT

    • GROUP BY

    • HAVING

    • LIMIT

    • UNIONUNION ALL

    • 選取清單中的子查詢

    • 對使用者變數的賦值

    • 僅參考文字值(在這種情況下,沒有底層表格)

如果最佳化器選擇實體化策略而不是合併衍生表,它會按以下方式處理查詢:

  • 最佳化器會延後衍生表的實體化,直到在查詢執行期間需要其內容時才進行。這可以提高效能,因為延遲實體化可能導致根本不必執行實體化。考慮一個將衍生表的結果與另一個表格連接的查詢:如果最佳化器先處理另一個表格,並發現它不返回任何列,則不需要進一步執行連接,並且最佳化器可以完全跳過實體化衍生表。

  • 在查詢執行期間,最佳化器可能會在衍生表中加入索引,以加速從中檢索列。

考慮以下 EXPLAIN 陳述式,用於包含衍生表的 SELECT 查詢:

EXPLAIN SELECT * FROM (SELECT * FROM t1) AS derived_t1;

最佳化器會透過延遲衍生表的實體化,直到在 SELECT 執行期間需要結果時才進行,來避免實體化衍生表。在這種情況下,不會執行查詢(因為它出現在 EXPLAIN 陳述式中),因此永遠不需要結果。

即使對於已執行的查詢,延遲衍生表的實體化也可能使最佳化器能夠完全避免實體化。當這種情況發生時,查詢執行速度會加快,因為節省了執行實體化所需的時間。考慮以下將衍生表的結果與另一個表格連接的查詢:

SELECT *
  FROM t1 JOIN (SELECT t2.f1 FROM t2) AS derived_t2
          ON t1.f2=derived_t2.f1
  WHERE t1.f1 > 0;

如果最佳化器先處理 t1,且 WHERE 子句產生空結果,則連接必定為空,且不需要實體化衍生表。

對於需要實體化衍生表的情況,最佳化器可能會在實體化表中加入索引,以加速對它的存取。如果這樣的索引能夠啟用對表格的 ref 存取,則可以大幅減少查詢執行期間讀取的資料量。考慮以下查詢:

SELECT *
 FROM t1 JOIN (SELECT DISTINCT f1 FROM t2) AS derived_t2
         ON t1.f1=derived_t2.f1;

如果這樣做能夠以最低成本的執行計畫使用 ref 存取,則最佳化器會從 derived_t2f1 欄位上建立索引。加入索引後,最佳化器可以將實體化衍生表視為帶有索引的常規表格,並從產生的索引中獲得類似的好處。與沒有索引的查詢執行成本相比,建立索引的開銷可以忽略不計。如果 ref 存取的成本高於其他存取方法,則最佳化器不會建立索引,也不會損失任何東西。

對於最佳化器追蹤輸出,已合併的衍生表或視圖參考不會顯示為節點。只有其底層表格才會出現在頂層查詢的計畫中。

適用於衍生表實體化的情況也適用於通用表表達式 (CTE)。此外,以下考量因素專門適用於 CTE。

如果 CTE 由查詢實體化,則該查詢只會實體化一次,即使查詢多次參考它也是如此。

遞迴 CTE 總是會被實體化。

如果 CTE 已實體化,則最佳化器會自動加入相關索引,如果它估計索引可以加速頂層陳述式對 CTE 的存取。這與衍生表的自動索引類似,不同之處在於,如果 CTE 被多次參考,最佳化器可能會建立多個索引,以最適合的方式加速每個參考的存取。

MERGENO_MERGE 最佳化器提示可以應用於 CTE。頂層陳述式中的每個 CTE 參考都可以有自己的提示,允許選擇性地合併或實體化 CTE 參考。以下陳述式使用提示來指示應合併 cte1,並應實體化 cte2

WITH
  cte1 AS (SELECT a, b FROM table1),
  cte2 AS (SELECT c, d FROM table2)
SELECT /*+ MERGE(cte1) NO_MERGE(cte2) */ cte1.b, cte2.d
FROM cte1 JOIN cte2
WHERE cte1.a = cte2.c;

CREATE VIEWALGORITHM 子句不會影響任何在視圖定義中 SELECT 陳述式之前的 WITH 子句的實體化。考慮這個陳述式:

CREATE ALGORITHM={TEMPTABLE|MERGE} VIEW v1 AS WITH ... SELECT ...

ALGORITHM 值只會影響 SELECT 的實體化,而不是 WITH 子句。

如先前所述,CTE 如果實體化,則會實體化一次,即使多次參考也是如此。為了指示一次性實體化,最佳化器追蹤輸出會包含一次 creating_tmp_table 的出現,再加上一次或多次 reusing_tmp_table 的出現。

CTE 類似於衍生表,其中 materialized_from_subquery 節點跟在參考之後。對於多次參考的 CTE 而言,也是如此,因此不會重複出現 materialized_from_subquery 節點(這會讓人覺得子查詢執行了多次,並產生不必要的冗長輸出)。只有對 CTE 的一個參考具有完整的 materialized_from_subquery 節點,其中包含其子查詢計畫的描述。其他參考具有簡化的 materialized_from_subquery 節點。相同的概念也適用於 TRADITIONAL 格式的 EXPLAIN 輸出:其他參考的子查詢不會顯示。