文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (美式信紙) - 40.0Mb
PDF (A4) - 40.1Mb
手冊頁 (TGZ) - 258.2Kb
手冊頁 (Zip) - 365.3Kb
資訊 (Gzip) - 4.0Mb
資訊 (Zip) - 4.0Mb


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

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 節「最佳化提示」

  • 類似地,您可以使用 derived_merge 旗標,該旗標位於 optimizer_switch 系統變數中。請參閱 第 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 子句不會影響任何 WITH 子句的實體化,該子句位於視圖定義中的 SELECT 陳述式之前。請考慮以下陳述式

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 輸出:不顯示其他參照的子查詢。