MySQL查詢優(yōu)化需要經(jīng)過解析、預(yù)處理和優(yōu)化三個(gè)步驟。在這些過程中,都有可能發(fā)生錯(cuò)誤。本篇文章不會(huì)深入討論錯(cuò)誤處理,而是幫助理解 MySQL 執(zhí)行查詢的方式,以便可以寫出更好的查詢語句。
一開始,MySQL 的解析器將查詢語句拆分成一系列指令并從中構(gòu)建一棵“解析樹”。解析器使用 MySQL 的SQL 語法去翻譯和驗(yàn)證查詢語句。例如,解析器保證了查詢中的指令是有效且次序正確,并且會(huì)檢查那種類似字符串引號(hào)未配對(duì)的錯(cuò)誤。
預(yù)處理器則檢查構(gòu)建好的解析樹中那些解析器無法處理的語義信息。例如,檢查數(shù)據(jù)表和列是否存在,并且處理字段名稱和別名以保證列引用沒有歧義。接下來,預(yù)處理器會(huì)檢查權(quán)限,通常這會(huì)非??欤ǔ悄愕姆?wù)端有一大堆權(quán)限配置)。
經(jīng)過解析器和預(yù)處理器后,解析樹就被確定是有效的了,可以被優(yōu)化器進(jìn)行處理并最終轉(zhuǎn)變?yōu)橐粋€(gè)查詢計(jì)劃。一個(gè)具有相同結(jié)果的查詢通常有很多種執(zhí)行方式,而優(yōu)化器的職責(zé)是找出其中最優(yōu)的選項(xiàng)。
MySQL使用基于代價(jià)估計(jì)的優(yōu)化器,這意味著它視圖預(yù)測眾多執(zhí)行計(jì)劃的代價(jià),并選擇代價(jià)最低的那個(gè)。最初的單位成本是隨機(jī)的4KB 數(shù)據(jù)頁讀取,而現(xiàn)在變得更為復(fù)雜,包括了如執(zhí)行 WHERE比較條件的代價(jià)??梢酝ㄟ^顯示 Last_query_cost 會(huì)話變量來查看查詢優(yōu)化器估計(jì)查詢語句的代價(jià)。
SELECT SQL_NO_CACHE COUNT(*) FROM sakila.film_actor; SHOW STATUS LIKE 'Last_query_cost';
顯示的 Last_query_cost 意味著優(yōu)化器估計(jì)需要執(zhí)行對(duì)應(yīng)次數(shù)的隨機(jī)數(shù)據(jù)頁訪問才能完成查詢。這是基于如下統(tǒng)計(jì)估算的結(jié)果:
優(yōu)化器并不會(huì)考慮估計(jì)內(nèi)容的緩存——它假設(shè)每次都從磁盤 I/O 讀取結(jié)果。優(yōu)化器并不是每次都能選擇最優(yōu)的執(zhí)行計(jì)劃,原因如下:
MySQL 查詢優(yōu)化器是其中非常復(fù)雜的一部分,使用了很多優(yōu)化方式將查詢語句轉(zhuǎn)換成為一個(gè)查詢執(zhí)行計(jì)劃。通常有兩種優(yōu)化方式:靜態(tài)優(yōu)化和動(dòng)態(tài)優(yōu)化。靜態(tài)優(yōu)化可以簡單地通過檢查解析樹進(jìn)行。例如,優(yōu)化器可以將 WHERE 條件通過數(shù)學(xué)運(yùn)算規(guī)則轉(zhuǎn)換成一個(gè)等式。靜態(tài)優(yōu)化與具體的值無關(guān),例如 WHERE條件的常量值。他們執(zhí)行一次后會(huì)一直有效,即便是查詢語句使用了不同的值再次執(zhí)行??梢岳斫鉃槭恰熬幾g時(shí)優(yōu)化”。
相反,動(dòng)態(tài)優(yōu)化是基于具體的情景的,并依賴于多種因素。例如,WHERE 條件中的值或索引中對(duì)應(yīng)的數(shù)據(jù)行數(shù)。這個(gè)過程在每次查詢都需要重新估計(jì),可以理解為是“運(yùn)行時(shí)優(yōu)化”。以下是一些 MySQL 的典型優(yōu)化方式:
EXPLAIN SELECT film.film_id, film_actor.actor_id FROM sakila.film INNER JOIN sakila.film_actor USING(film_id) WHERE film.film_id = 1;
MySQL 會(huì)將這個(gè)查詢拆分為2步,因此分析結(jié)果會(huì)有兩行。第一步是是在 film 表中查找對(duì)應(yīng)的數(shù)據(jù)行。由于 是按主鍵film_id查詢的,MySQL 知道只有一行數(shù)據(jù)。 因此,此時(shí)的查詢分析結(jié)果的 ref 是常量。在第二步中,MySQL 會(huì)將 film_id 作為已知值,因此對(duì) film_actor 的查詢的 ref 也是常量。其他類似的場景還有 WHERE,USING或 ON 條件中的約束條件是等式。在這個(gè)例子中,MySQL 知道 USING條件的 film_id 在查詢語句中都是相同的值,這個(gè)值必須和 WHERE條件的 film_id 相同。
EXPLAIN SELECT film.film_id FROM sakila.film WHERE film_id=1;
在分析結(jié)果中的 Extra字段會(huì)看到“Impossible WHERE noticed after reading const tables”。在其他情形也會(huì)有提前中止的情況,例如:
SELECT film.film_id FROM sakila.film LEFT OUTER JOIN sakila.film_actor USING(film_id) WHERE sakila.film_actor.film_id IS NULL;
這個(gè)查詢排除那些有演員的電影。每部電源都可能有多名演員,但是只要找到一名演員后,MySQL 就會(huì)停止處理當(dāng)前的這部電影,而去處理下一部。對(duì)于 DISTINCT,NOT EXISTS 也會(huì)有類似的情況。
SELECT film.film_id FROM sakila.film INNER JOIN sakila.film_actor USING(film_id) WHERE film.film_id > 500;
MySQL 會(huì)知道 WHERE 條件的約束不僅適用于 film 表,同樣也適用于 film_actor 表。但對(duì)于其他數(shù)據(jù)庫則未必會(huì)有這樣的優(yōu)化效果。
實(shí)際上,MySQL 使用的優(yōu)化手段比上述列舉的多得多,這里沒法一一列舉。只是需要記住 MySQL 的優(yōu)化器的復(fù)雜性及其智能化程度。因此,應(yīng)當(dāng)讓優(yōu)化器發(fā)揮其作用,而不是無限優(yōu)化查詢語句直到 MySQL 的優(yōu)化器沒有用武之地。當(dāng)然,雖然 MySQL 的優(yōu)化器很聰明,但是它給出的并不一定是最優(yōu)結(jié)果,有些時(shí)候你知道最優(yōu)結(jié)果,而 MySQL 未必知道。這種情況下,你可以對(duì)查詢語句進(jìn)行優(yōu)化從而幫助 MySQL 完成優(yōu)化工作,而有些時(shí)候則需要增加查詢的提示,或是重寫查詢,修改數(shù)據(jù)表設(shè)計(jì)或增加索引。
以上就是理解MySQL查詢優(yōu)化處理過程的詳細(xì)內(nèi)容,更多關(guān)于MySQL 查詢優(yōu)化的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!
標(biāo)簽:龍巖 南充 麗水 無錫 迪慶 徐州 西寧 自貢
巨人網(wǎng)絡(luò)通訊聲明:本文標(biāo)題《理解MySQL查詢優(yōu)化處理過程》,本文關(guān)鍵詞 理解,MySQL,查詢,優(yōu)化,處理,;如發(fā)現(xiàn)本文內(nèi)容存在版權(quán)問題,煩請(qǐng)?zhí)峁┫嚓P(guān)信息告之我們,我們將及時(shí)溝通與處理。本站內(nèi)容系統(tǒng)采集于網(wǎng)絡(luò),涉及言論、版權(quán)與本站無關(guān)。