4.2 MySQL查詢優化程序
在發布一個選擇行的查詢時, MySQL進行分析,看是否能夠對它進行優化,使它執行更快。本節中,我們將研究查詢優化程序怎樣工作。更詳細的信息,可參閱MySQL參考指南中的“Getting Maximum Performance from MySQL”,該章描述了MySQL采用的各種優化措
施。該章中的信息會不斷變化,因為MySQL的開發者不斷對優化程序進行改進,因此,有必要經常拜訪一下該章,看看是否有可供利用的新技巧。(http://www.mysql.com/ 處的MySQL聯機參考指南在不斷地更新。)
MySQL查詢優化程序利用了索引。當然,它也利用了其他信息。例如,如果發布下列查詢,MySQL將非常快地執行它,不管相應的表有多大:
SELECT * FROM tb1_name WHERE 1= 0
在此情形中,MySQL考察WHERE 子句,如果認識到不可能有滿足該查詢的行,就不會對該表進行搜索。可利用EXPLAIN 語句知道這一點,EXPLAIN 語句要求MySQL顯示某些有關它應該執行一條SELECT 查詢,而實際沒有執行的信息。為了使用E X P L A I N,只需要SELECT 語句前放置EXPLAIN 即可,如下所示:
EXPLAIN SELECT * FROM tb1_name WHERE 1= 0
通常,EXPLAIN 返回的信息比這個多,包括將用來掃描表的索引、將要使用的連接類型以及需要在每個表中掃描的行數估計等等。
4.2.1優化程序怎樣工作
MySQL查詢優化程序有幾個目標,但其主要目標是盡量利用索引,而且盡量使用最具有限制性的索引以排除盡可能多的行。這樣做可能會適得其反,因為發布一條SELECT 語句的目的是尋找行,而不是拒絕它們。優化程序這樣工作的原因是從要考慮的行中排除行越快,那麼找到確實符合給出標准的行就越快。如果能夠首先進行最具限制性的測試,則查詢可以進行得更快。假如有一個測試兩列的查詢,每列上都有一個索引:
WHERE coll = "some value" AND col2 = "some other value"
還假定,與col1上的測試相符的有900 行,與col2 上的測試相符的有300 行,而兩個測試都通過的有30 行。如果首先測試c o l 1,必須檢查900 行以找到也與col2 值相符的30 行。那麼測試中有870 將失敗。如果首先測試c o l 2,要找到也與col1值相符的30 行,只需檢查300 行。測試中有失敗270 次,這樣所涉及的計算較少,磁盤I/O 也較少。遵循下列准則,有助於優化程序利用索引:
■ 比較具有相同類型的列。在比較中利用索引列時,應該使用那些類型相同的列。例如,CHAR(10) 被視為與CHAR(10) 或VARCHAR(10) 相同,但不同於CHAR(12) 和VARCHAR( 12 )。INT 與BIGINT 不同。在MySQL3.23 版以前,要求使用相同類型的
列,否則列上的索引將不起作用。自3.23 版後,不嚴格要求這樣做,但相同的列類型比不同類型提供更好的性能。如果所比較的兩列類型不同,可使用ALTER TABLE語句修改其中之一使它們的類型相配。
■ 比較中應盡量使索引列獨立。如果在函數調用或算術表達式中使用一個列,則MySQL不能使用這樣的索引,因為它必須對每行計算表達式的值。有時,這是不可避免的,但很多時候,可以重新編寫只取索引列本身的查詢。下面的WHERE 子句說明了怎樣進行這項工作。第一行中,優化程序將簡化表達式4/2 為值2,然後使用my_col 上的索引快速地找到小於2 的值。而在第二個表達式中,MySQL必須檢索出每行的my_col 值,乘以2,然後將結果與4 比較。沒索引可用,因為列中的每個值都要檢索,以便能對左邊的表達式求值:
WHERE my_col < 4/2
WHERE my_col * 2 < 4
讓我們考慮另一個例子。假如有一個索引列date _ c o l。如果發布如下的查詢,相應的索引未被使用:
SELECT * FROM my_tb1WHERE YEAR(date_col) < 1990
其中表達式並不將索引列與1990 比較,而是將從列值計算出的值用於比較,而且必須計算每行的這個值。結果是, date_col 上的索引不可能得到使用。怎樣解決?使用一個文字日期即可,這時將會使用date_col 上的索引:
WHERE date_col < "1990-01-01"
但是假如沒有特定的日期值,那麼可能會對找到具有出現在距今一定天數內的日期的記錄感興趣。有幾種方法來編寫這樣的查詢,但並非所有方法都很好。三種可能的方法如下: