本節討論可以對處理 WHERE
子句進行的最佳化。範例使用 SELECT
語法,但相同的最佳化適用於 DELETE
和 UPDATE
語法中的 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(*)
會直接從MyISAM
和MEMORY
資料表的資料表資訊中擷取。這也適用於僅與單一資料表搭配使用的任何NOT NULL
表達式。早期偵測無效的常數表達式。MySQL 會快速偵測到某些
SELECT
語法是不可能的,並且不傳回任何列。對於聯結中的每個資料表,會建構一個更簡單的
WHERE
,以快速評估資料表的WHERE
,並儘快跳過列。所有常數資料表會在查詢中的任何其他資料表之前讀取。常數資料表可以是下列任何一種
空資料表或只有一列的資料表。
一個在
PRIMARY KEY
或UNIQUE
索引上使用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 BY
和GROUP BY
子句中的所有欄位都來自同一個資料表,則在聯結時會優先選擇該資料表。如果存在
ORDER BY
子句和不同的GROUP BY
子句,或者ORDER BY
或GROUP 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, ... ;