av婷婷久久网,91视频这里只有精品,91午夜福利一区二区,啊啊啊一区二区久久久,啪啪亚洲视频,www.插插,亚洲婷婷精品二区,开心五月激情射,久青草在在线

你好,歡迎您來到福建信息主管(CIO)網(wǎng)! 設(shè)為首頁|加入收藏|會員中心
您現(xiàn)在的位置:>> 新聞資訊 >>
MySQL查詢優(yōu)化系列講座之查詢優(yōu)化器
作者:陶剛編譯 來源:天極yesky 發(fā)布時間:2005年09月23日 點擊數(shù):
當(dāng)你提交一個查詢的時候,MySQL會分析它,看是否可以做一些優(yōu)化使處理該查詢的速度更快。這一部分將介紹查詢優(yōu)化器是如何工作的。如果你想知道MySQL采用的優(yōu)化手段,可以查看MySQL參考手冊。

  當(dāng)然,MySQL查詢優(yōu)化器也利用了索引,但是它也使用了其它一些信息。例如,如果你提交如下所示的查詢,那么無論數(shù)據(jù)表有多大,MySQL執(zhí)行它的速度都會非??欤?BR />
SELECT * FROM tbl_name WHERE 0;

  在這個例子中,MySQL查看WHERE子句,認識到?jīng)]有符合查詢條件的數(shù)據(jù)行,因此根本就不考慮搜索數(shù)據(jù)表。你可以通過提供一個EXPLAIN語句看到這種情況,這個語句讓MySQL顯示自己執(zhí)行的但實際上沒有真正地執(zhí)行的SELECT查詢的一些信息。如果要使用EXPLAIN,只需要在EXPLAIN單詞放在SELECT語句的前面:

mysql> EXPLAIN SELECT * FROM tbl_name WHERE 0\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: NULL
type: NULL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: NULL
Extra: Impossible WHERE

  通常情況下,EXPLAIN返回的信息比上面的信息要多一些,還包括用于掃描數(shù)據(jù)表的索引、使用的聯(lián)結(jié)類型、每張數(shù)據(jù)表中估計需要檢查的數(shù)據(jù)行數(shù)量等非空(NULL)信息。

  優(yōu)化器是如何工作的

  MySQL查詢優(yōu)化器有幾個目標,但是其中最主要的目標是盡可能地使用索引,并且使用最嚴格的索引來消除盡可能多的數(shù)據(jù)行。你的最終目標是提交SELECT語句查找數(shù)據(jù)行,而不是排除數(shù)據(jù)行。優(yōu)化器試圖排除數(shù)據(jù)行的原因在于它排除數(shù)據(jù)行的速度越快,那么找到與條件匹配的數(shù)據(jù)行也就越快。如果能夠首先進行最嚴格的測試,查詢就可以執(zhí)行地更快。假設(shè)你的查詢檢驗了兩個數(shù)據(jù)列,每個列上都有索引:

SELECT col3 FROM mytable
WHERE col1 = ’some value’ AND col2 = ’some other value’;

  假設(shè)col1上的測試匹配了900個數(shù)據(jù)行,col2上的測試匹配了300個數(shù)據(jù)行,而同時進行的測試只得到了30個數(shù)據(jù)行。先測試Col1會有900個數(shù)據(jù)行,需要檢查它們找到其中的30個與col2中的值匹配記錄,其中就有870次是失敗了。先測試col2會有300個數(shù)據(jù)行,需要檢查它們找到其中的30個與col1中的值匹配的記錄,只有270次是失敗的,因此需要的計算和磁盤I/O更少。其結(jié)果是,優(yōu)化器會先測試col2,因為這樣做開銷更小。

  你可以通過下面一個指導(dǎo)幫助優(yōu)化器更好地利用索引:

  盡量比較數(shù)據(jù)類型相同的數(shù)據(jù)列。當(dāng)你在比較操作中使用索引數(shù)據(jù)列的時候,請使用數(shù)據(jù)類型相同的列。相同的數(shù)據(jù)類型比不同類型的性能要高一些。例如,INT與BIGINT是不同的。CHAR(10)被認為是CHAR(10)或VARCHAR(10),但是與CHAR(12)或VARCHAR(12)不同。如果你所比較的數(shù)據(jù)列的類型不同,那么可以使用ALTER TABLE來修改其中一個,使它們的類型相匹配。

  盡可能地讓索引列在比較表達式中獨立。如果你在函數(shù)調(diào)用或者更復(fù)雜的算術(shù)表達式條件中使用了某個數(shù)據(jù)列,MySQL就不會使用索引,因為它必須計算出每個數(shù)據(jù)行的表達式值。有時候這種情況無法避免,但是很多情況下你可以重新編寫一個查詢讓索引列獨立地出現(xiàn)。

  下面的WHERE子句顯示了這種情況。它們的功能相同,但是對于優(yōu)化目標來說就有很大差異了:

WHERE mycol < 4 / 2
WHERE mycol * 2 < 4

  對于第一行,優(yōu)化器把表達式4/2簡化為2,接著使用mycol上的索引來快速地查找小于2的值。對于第二個表達式,MySQL必須檢索出每個數(shù)據(jù)行的mycol值,乘以2,接著把結(jié)果與4進行比較。在這種情況下,不會使用索引。數(shù)據(jù)列中的每個值都必須被檢索到,這樣才能計算出比較表達式左邊的值。

  我們看另外一個例子。假設(shè)你對date_col列進行了索引。如果你提交一條如下所示的查詢,就不會使用這個索引:

SELECT * FROM mytbl WHERE YEAR(date_col) < 1990;

  這個表達式不會把1990與索引列進行比較;它會把1990與該數(shù)據(jù)列計算出來的值比較,而每個數(shù)據(jù)行都必須計算出這個值。其結(jié)果是,沒有使用date_col上的索引,因為執(zhí)行這樣的查詢需要全表掃描。怎么解決這個問題呢?只需要使用文本日期,接著就可以使用date_col上的索引來查找列中匹配的值了:

WHERE date_col < ’1990-01-01’

  但是,假設(shè)你沒有特定的日期。你可能希望找到一些與今天相隔固定的幾天的日期的記錄。表達這種類型的比較有很多種方法--它們的效率并不同。下面就有三種:

WHERE TO_DAYS(date_col) - TO_DAYS(CURDATE()) < cutoff
WHERE TO_DAYS(date_col) < cutoff + TO_DAYS(CURDATE())
WHERE date_col < DATE_ADD(CURDATE(), INTERVAL cutoff DAY)

  對于第一行,不會用到索引,因為每個數(shù)據(jù)行都必須檢索以計算出TO_DAYS(date_col)的值。第二行要好一些。Cutoff和TO_DAYS(CURDATE())都是常量,因此在處理查詢之前,比較表達式的右邊可以被優(yōu)化器一次性計算出來,而不需要每個數(shù)據(jù)行都計算一次。但是date_col列仍然出現(xiàn)在函數(shù)調(diào)用中,它阻止了索引的使用。第三行是這幾個中最好的。同樣,在執(zhí)行查詢之前,比較表達式的右邊可以作為常量一次性計算出來,但是現(xiàn)在它的值是一個日期。這個值可以直接與date_col值進行比較,再也不需要轉(zhuǎn)換成天數(shù)了。在這種情況下,會使用索引。

  在LIKE模式的開頭不要使用通配符。有些字符串搜索使用如下所示的WHERE子句:

WHERE col_name LIKE ’%string%’

  如果你希望找到那些出現(xiàn)在數(shù)據(jù)列的任何位置的字符串,這個語句就是對的。但是不要因為習(xí)慣而簡單地把"%"放在字符串的兩邊。如果你在查找出現(xiàn)在數(shù)據(jù)列開頭的字符串,就刪掉前面的"%"。假設(shè)你要查找那些類似MacGregor或MacDougall等以"Mac"開頭的名字。在這種情況下,WHERE子句如下所示:

WHERE last_name LIKE ’Mac%’

  優(yōu)化器查看該模式中詞首的文本,并使用索引找到那些與下面的表達式匹配的數(shù)據(jù)行。下面的表達式是使用last_name索引的另一種形式:

WHERE last_name >= ’Mac’ AND last_name < ’Mad’


  這種優(yōu)化不能應(yīng)用于使用了REGEXP操作符的模式匹配。REGEXP表達式永遠不會被優(yōu)化。
幫助優(yōu)化器更好的判斷索引的效率。在默認情況下,當(dāng)你把索引列的值與常量進行比較的時候,優(yōu)化器會假設(shè)鍵值在索引內(nèi)部是均勻分布的。在決定進行常量比較是否使用索引的時候,優(yōu)化器會快速地檢查索引,估計出會用到多少個實體(entry)。對應(yīng)MyISAM、InnoDB和BDB數(shù)據(jù)表來說,你可以使用ANALYZE TABLE讓服務(wù)器執(zhí)行對鍵值的分析。它會為優(yōu)化器提供更好的信息。

  使用EXPLAIN驗證優(yōu)化器的操作。EXPLAIN語句可以告訴你是否使用了索引。當(dāng)你試圖用另外的方式編寫語句或檢查添加索引是否會提高查詢執(zhí)行效率的時候,這些信息對你是有幫助的。

  在必要的時候給優(yōu)化器一些提示。正常情況下,MySQL優(yōu)化器自由地決定掃描數(shù)據(jù)表的次序來最快地檢索數(shù)據(jù)行。在有些場合中優(yōu)化器沒有作出最佳選擇。如果你察覺這種現(xiàn)象發(fā)生了,就可以使用STRAIGHT_JOIN關(guān)鍵字來重載優(yōu)化器的選擇。帶有STRAIGHT_JOIN的聯(lián)結(jié)類似于交叉聯(lián)結(jié),但是強迫數(shù)據(jù)表按照FROM子句中指定的次序來聯(lián)結(jié)。

  在SELECT語句中有兩個地方可以指定STRAIGHT_JOIN。你可以在SELECT關(guān)鍵字和選擇列表之間的位置指定,這樣會對語句中所有的交叉聯(lián)結(jié)產(chǎn)生影響;你也可以在FROM子句中指定。下面的兩個語句功能相同:

SELECT STRAIGHT_JOIN ... FROM t1, t2, t3 ... ;
SELECT ... FROM t1 STRAIGHT_JOIN t2 STRAIGHT_JOIN t3 ... ;

  分別在帶有STRAIGHT_JOIN和不帶STRAIGHT_JOIN的情況下運行這個查詢;MySQL可能因為什么原因沒有按照你認為最好的次序使用索引(你可以使用EXPLAIN來檢查MySQL處理每個語句的執(zhí)行計劃)。

  你還可以使用FORCE INDEX、USE INDEX或IGNORE INDEX來指導(dǎo)服務(wù)器如何使用索引。

  利用優(yōu)化器更加完善的區(qū)域。MySQL可以執(zhí)行聯(lián)結(jié)和子查詢,但是子查詢是最近才支持的,是在MySQL 4.1中添加的。因而在很多情況下,優(yōu)化器對聯(lián)結(jié)操作的調(diào)整比對子查詢的調(diào)整要好一些。當(dāng)你的子查詢執(zhí)行地很慢的時候,這就是一條實際的提示。有一些子查詢可以使用邏輯上相等的聯(lián)結(jié)來重新表達。在可行的情況下,你可以把子查詢重新改寫為聯(lián)結(jié),看是否執(zhí)行地快一些。

  測試查詢的備用形式,多次運行。當(dāng)你測試查詢的備用形式的時候(例如,子查詢與等同的聯(lián)結(jié)操作對比),每種方式都應(yīng)該多次運行。如果兩種形式都只運行了一次,那么你通常會發(fā)現(xiàn)第二個查詢比第一個快,這是因為第一個查詢得到的信息仍然保留在緩存中,以至于第二個查詢沒有真正地從磁盤上讀取數(shù)據(jù)。你還應(yīng)該在系統(tǒng)負載相對平穩(wěn)的時候運行查詢,以避免系統(tǒng)中其它的事務(wù)影響結(jié)果。

  避免過度地使用MySQL自動類型轉(zhuǎn)換。MySQL會執(zhí)行自動的類型轉(zhuǎn)換,但是如果你能夠避免這種轉(zhuǎn)換操作,你得到的性能就更好了。例如,如果num_col是整型數(shù)據(jù)列,那么下面這些查詢將返回相同的結(jié)果:

SELECT * FROM mytbl WHERE num_col = 4;
SELECT * FROM mytbl WHERE num_col = ’4’;

  但是第二個查詢涉及到了類型轉(zhuǎn)換。轉(zhuǎn)換操作本身為了把整型和字符串型轉(zhuǎn)換為雙精度型進行比較,使性能惡化了。更嚴重的情況是,如果num_col是索引的,那么涉及到類型轉(zhuǎn)換的比較操作不會使用索引。

  相反類型的比較操作(把字符串列與數(shù)值比較)也會阻止索引的使用。假設(shè)你編寫了如下所示的查詢:

SELECT * FROM mytbl WHERE str_col = 4;

  在這個例子中,不會使用str_col上的索引,因為在把str_col中的字符串值轉(zhuǎn)換成數(shù)值的時候,可能有很多值等于4(例如’4’、’4.0’和’4th’)。分辨哪些值符合要求的唯一辦法是讀取每個數(shù)據(jù)行并執(zhí)行比較操作。
使用EXPLAIN來檢查優(yōu)化器的操作

  EXPLAIN對于了解優(yōu)化器生成的、用于處理語句的執(zhí)行計劃的內(nèi)部信息是很有幫助的。在這一部分中,我們將解釋EXPLAIN的兩種用途:

  · 查看采用不同的方式編寫的查詢是否影響了索引的使用。

  · 查看向數(shù)據(jù)表添加索引對優(yōu)化器生成高效率執(zhí)行計劃的能力的影響。

  這一部分只討論與示例相關(guān)的EXPLAIN輸入字段。

  前面,在"優(yōu)化器是如何工作的"部分中我們得出的觀點是,你編寫表達式的方式將決定優(yōu)化器是否能使用可用的索引。特別是上面的討論使用了下面三個邏輯相等的WHERE子句的例子,只有第三個允許使用索引:

WHERE TO_DAYS(date_col) - TO_DAYS(CURDATE()) < cutoff
WHERE TO_DAYS(date_col) < cutoff + TO_DAYS(CURDATE())
WHERE date_col < DATE_ADD(CURDATE(), INTERVAL cutoff DAY)

  EXPLAIN允許你查看編寫表達式的某種方式是否比另外的方式好一些。為了看到結(jié)果,讓我們分別用這三個WHERE子句搜索成員表中過期的數(shù)據(jù)列值,把cutoff值設(shè)為30天。為了看到索引的使用和表達式編寫方式之間的關(guān)系,我們首先對expiration列進行索引:

mysql> ALTER TABLE member ADD INDEX (expiration);

  接著在每個表達式形式上使用EXPLAIN,看優(yōu)化器生成了什么樣的執(zhí)行計劃:

mysql> EXPLAIN SELECT * FROM MEMBER
-> WHERE TO_DAYS(expiration) - TO_DAYS(CURDATE()) < 30\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: MEMBER
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 102
Extra: Using where
mysql> EXPLAIN SELECT * FROM MEMBER
-> WHERE TO_DAYS(expiration) < 30 + TO_DAYS(CURDATE())\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: MEMBER
type: ALL
possible_keys: NULL
key: NULL
key_len: NULL
ref: NULL
rows: 102
Extra: Using where
mysql> EXPLAIN SELECT * FROM MEMBER
-> WHERE expiration < DATE_ADD(CURDATE(), INTERVAL 30 DAY)\G
*************************** 1. row ***************************
id: 1
select_type: SIMPLE
table: MEMBER
type: range
possible_keys: expiration
key: expiration
key_len: 4
ref: NULL
rows: 6
Extra: Using where

  上面的結(jié)果顯示,前面兩個語句沒有使用索引。類型(type)值表明了將如何從數(shù)據(jù)表中讀取信息。ALL意味著"將檢查所有的記錄"。也就是說,它會執(zhí)行全表掃描,沒有利用索引。每個與鍵相關(guān)的列都是NULL也表明沒有使用索引。

  與此形成對比的是,第三個語句的結(jié)果顯示,采用這種方式編寫的WHERE子句,優(yōu)化器可以使用expiration列上的索引:

  · 類型(type)值表明它可以使用索引來搜索特定范圍的值(小于右邊表達式給定的值)。

  · 可能鍵(possible_keys)和鍵(key)值顯示expiration上的索引已經(jīng)被考慮作為備選索引,并且它也是真正使用的索引。

  · 行數(shù)(rows)值顯示優(yōu)化器估計自己需要檢查6個數(shù)據(jù)行來處理該查詢。這比前面兩個執(zhí)行計劃的102小很多。

  EXPLAIN的第二種用途是查看添加索引是否能幫助優(yōu)化器更高效率地執(zhí)行語句。我將使用兩個未被索引的數(shù)據(jù)表。它足夠顯示建立索引的效率。相同的規(guī)則可以應(yīng)用于涉及多表的更加復(fù)雜的聯(lián)結(jié)操作。

  假設(shè)我們有兩個數(shù)據(jù)表t1和t2,每個有1000行,包含的值從1到1000。下面的查詢查找出兩個表中值相同的數(shù)據(jù)行:

宝山区| 富阳市| 侯马市| 清苑县| 加查县| 延安市| 曲靖市| 昌江| 贞丰县| 靖江市| 噶尔县| 永靖县| 察哈| 龙胜| 垫江县| 萝北县| 芜湖市| 大冶市| 泰顺县| 铜陵市| 海安县| 托克逊县| 遵义县| 淮阳县| 宝鸡市| 收藏| 简阳市| 兰州市| 孟村| 福清市| 章丘市| 克什克腾旗| 兴山县| 文水县| 定结县| 敦化市| 武夷山市| 新源县| 西乡县| 邹平县| 长丰县|