文件首頁
MySQL 9.0 參考手冊
相關文件 下載本手冊
PDF (US Ltr) - 40.0Mb
PDF (A4) - 40.1Mb
Man Pages (TGZ) - 258.2Kb
Man Pages (Zip) - 365.3Kb
Info (Gzip) - 4.0Mb
Info (Zip) - 4.0Mb


MySQL 9.0 參考手冊  /  ...  /  WHERE 子句最佳化

10.2.1.1 WHERE 子句最佳化

本節討論可以對處理 WHERE 子句進行的最佳化。範例使用 SELECT 陳述式,但相同的最佳化也適用於 DELETEUPDATE 陳述式中的 WHERE 子句。

注意

由於 MySQL 最佳化工具的工作正在進行中,因此並非所有 MySQL 執行的最佳化都記錄在此處。

您可能會想重寫查詢以加快算術運算的速度,同時犧牲可讀性。由於 MySQL 會自動進行類似的最佳化,因此您通常可以避免這項工作,並將查詢保留在更容易理解和維護的形式中。MySQL 執行的一些最佳化如下

  • 移除不必要的括號

       ((a AND b) AND c OR (((a AND b) AND (c AND d))))
    -> (a AND b AND c) OR (a AND b AND c AND d)
  • 常數摺疊

       (a<b AND b=c) AND a=5
    -> b>5 AND b=c AND a=5
  • 常數條件移除

       (b>=5 AND b=5) OR (b=6 AND 5=5) OR (b=7 AND 5=6)
    -> b=5 OR b=6

    這發生在準備階段而非最佳化階段,這有助於簡化聯結。如需更多資訊和範例,請參閱 第 10.2.1.9 節,〈外部聯結最佳化〉

  • 索引使用的常數運算式只會評估一次。

  • 會檢查數值類型資料行與常數值的比較,並針對無效或超出範圍的值進行摺疊或移除

    # CREATE TABLE t (c TINYINT UNSIGNED NOT NULL);
      SELECT * FROM t WHERE c ≪ 256;
    -≫ SELECT * FROM t WHERE 1;

    如需更多資訊,請參閱 第 10.2.1.14 節,〈常數摺疊最佳化〉

  • 在沒有 WHERE 的單一資料表上使用 COUNT(*) 時,會直接從 MyISAMMEMORY 資料表的資料表資訊中擷取。當只使用一個資料表時,任何 NOT NULL 運算式也會執行此動作。

  • 早期偵測無效的常數運算式。MySQL 會快速偵測到某些 SELECT 陳述式不可能,且不傳回任何資料列。

  • 如果您未使用 GROUP BY 或彙總函式(COUNT()MIN() 等),則 HAVING 會與 WHERE 合併。

  • 對於聯結中的每個資料表,會建構一個較簡單的 WHERE,以取得該資料表的快速 WHERE 評估,並儘快略過資料列。

  • 所有常數資料表都會在查詢中的任何其他資料表之前先讀取。常數資料表是下列任何一種

    • 空的資料表或只有一個資料列的資料表。

    • PRIMARY KEYUNIQUE 索引上使用 WHERE 子句的資料表,其中所有索引部分都會與常數運算式進行比較,並定義為 NOT NULL

    所有下列資料表都用作常數資料表

    SELECT * FROM t WHERE primary_key=1;
    SELECT * FROM t1,t2
      WHERE t1.primary_key=1 AND t2.primary_key=t1.id;
  • 藉由嘗試所有可能性來找出聯結資料表的最佳聯結組合。如果 ORDER BYGROUP BY 子句中的所有資料行都來自同一個資料表,則聯結時會優先選取該資料表。

  • 如果存在 ORDER BY 子句和不同的 GROUP BY 子句,或者如果 ORDER BYGROUP BY 包含來自聯結佇列中第一個資料表以外之資料表的資料行,則會建立暫存資料表。

  • 如果您使用 SQL_SMALL_RESULT 修飾詞,則 MySQL 會使用記憶體中的暫存資料表。

  • 系統會查詢每個資料表的索引,並使用最佳索引,除非最佳化工具認為使用資料表掃描會更有效率。過去,是否使用掃描取決於最佳索引是否涵蓋超過資料表的 30%,但現在不再由固定的百分比來決定使用索引或掃描。最佳化工具現在更複雜,其估計依據額外的因素,例如資料表大小、行數和 I/O 區塊大小。

  • 在某些情況下,MySQL 可以直接從索引讀取資料列,而無需查詢資料檔案。如果索引中使用的所有欄位都是數值類型,則僅使用索引樹來解析查詢。

  • 在輸出每一列之前,會跳過那些不符合 HAVING 子句的資料列。

以下是一些執行速度非常快的查詢範例

SELECT COUNT(*) FROM tbl_name;

SELECT MIN(key_part1),MAX(key_part1) FROM tbl_name;

SELECT MAX(key_part2) FROM tbl_name
  WHERE key_part1=constant;

SELECT ... FROM tbl_name
  ORDER BY key_part1,key_part2,... LIMIT 10;

SELECT ... FROM tbl_name
  ORDER BY key_part1 DESC, key_part2 DESC, ... LIMIT 10;

假設索引欄位為數值類型,MySQL 會僅使用索引樹來解析以下查詢

SELECT key_part1,key_part2 FROM tbl_name WHERE key_part1=val;

SELECT COUNT(*) FROM tbl_name
  WHERE key_part1=val1 AND key_part2=val2;

SELECT MAX(key_part2) FROM tbl_name GROUP BY key_part1;

以下查詢會使用索引以排序的順序擷取資料列,而無需單獨進行排序

SELECT ... FROM tbl_name
  ORDER BY key_part1,key_part2,... ;

SELECT ... FROM tbl_name
  ORDER BY key_part1 DESC, key_part2 DESC, ... ;