7.2.4.MySQL怎樣優化WHERE子句
7.2.4. MySQL怎樣優化WHERE子句
該節討論為處理WHERE子句而進行的優化。例子中使用了SELECT語句,但相同的優化也適用DELETE和UPDATE語句中的WHERE子句。
請注意對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
· 索引使用的常數表達式僅計算一次。
- 對于MyISAM和HEAP表,在一個單個表上的沒有一個WHERE的COUNT(*)直接從表中檢索信息。當僅使用一個表時,對NOT NULL表達式也這樣做。
- 無效常數表達式的早期檢測。MySQL快速檢測某些SELECT語句是不可能的并且不返回行。
- 如果不使用GROUP BY或分組函數(COUNT()、MIN()……),HAVING與WHERE合并。
- 對于聯接內的每個表,構造一個更簡單的WHERE以便更快地對表進行WHERE計算并且也盡快跳過記錄。
- 所有常數的表在查詢中比其它表先讀出。常數表為:
- 空表或只有1行的表。
- 與在一個PRIMARY KEY或UNIQUE索引的WHERE子句一起使用的表,這里所有的索引部分使用常數表達式并且索引部分被定義為NOT NULL。
下列的所有表用作常數表:
mysql> SELECT * FROM t WHERE primary_key=1;
mysql> 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;
下列查詢僅使用索引樹就可以解決(假設索引的列為數值型):
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 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, ... ;