天天看點

【1】Mysql學習筆記:Mysql的一條查詢語句是如何執行的?

在這裡,我們以

select * from table where id = 10

為例子,進行查詢。

Mysql基本架構示意圖:

用戶端+ server層+存儲引擎層:

【1】Mysql學習筆記:Mysql的一條查詢語句是如何執行的?

Server層:包括連接配接器、查詢緩存、分析器、優化器、執行器等,涵蓋Mysql的大多數核心服務功能,以及所有的内置函數(比如:日期、時間、數學和加密函數等),所有跨存儲引擎的功能,都在這一層實作,比如存儲過程、觸發器、師徒等。

存儲引擎層負責資料的存儲和提取,其架構模式是插件式、支援InnoDB、MyISAM、Memory等多個存儲引擎。

mysql的存儲引擎預設的是InnoDB。執行creatable table語句的時候,如果沒有指定存儲引擎的類型,預設選取的就是InnoDB、但是也可以通過指定存儲引擎的類型,來選擇存儲引擎,建立表。

連接配接器:

第一步,你會先連接配接到這個資料庫上,這時候接待你的就是連接配接器。連接配接器負責跟用戶端建立連接配接、擷取權限、維持和管理連接配接。

連接配接指令中,mysql是用戶端的工具,用來跟服務端履歷連接配接。在完成經典的TCP握手後,連接配接器,就要開始認證你的身份,這個時候,這個時候用的就是你輸入的使用者名和密碼。

如果使用者名或者密碼不對,你就會收到一個access denied for user的錯誤,然後用戶端程式,結束執行。

如果使用者名和密碼認證通過,連接配接器就會到權限表裡檢查出,你擁有的權限,之後,這個連結裡面的權限邏輯判斷,都将依賴于此時讀到的權限。

這就意味着,一個使用者成功建立連接配接後,即使你用管理者賬号,對這個使用者的權限做了修改,也不會影響到已經存在的連接配接。修改完成後,隻有再建立連接配接時才會使用新的權限設定。

連接配接完成後,如果你沒有後續的動作,這個連接配接,就處于空閑狀态,你可以在showprocesslist指令中看到它,文本中這個圖是show processlist的結果,其中的command列顯示為sleep的這一行,就表示現在系統裡面有一個空閑連接配接。

如果連接配接被切斷之後,用戶端再次發送請求的話,就會收到一個錯誤提醒:lost connection to mysql server during query。這個時候如果你要繼續,就需要重新連接配接,然後在執行請求了。

資料庫裡面,長連接配接,是指連接配接成功後,如果用戶端持續有請求,則一直使用同一個連接配接。短連接配接,則是值每次執行完成很少的幾次查詢,就斷開連接配接,下次重建立立一個新的連接配接。

建立連接配接的動作比較複雜,耗時,是以在使用中,盡量減少連接配接的動作,也就是盡量使用長連接配接。

但是全部使用長連接配接以後,你可能會發現,有些時候mysql占用記憶體漲的特别快,這是因為Mysql 在執行的過程中,臨時使用的記憶體是關聯在連接配接對象裡面的。這些資源會在連接配接斷開的時候,才能釋放。是以若果昌連接配接累計下來,可能導緻記憶體占用太大,被系統強行殺掉,從現象來看,就是Mysql重新開機了。

怎麼解決這個問題,可以考慮以下兩種方案。

[1]定時斷開長連接配接。使用一段時間後,或者程式裡判斷,執行過一個占用記憶體的大查詢之後,斷開連接配接,之後查詢重建立立連接配接。

[2] 如果使用的是Mysql 5.7或者更新的版本。可以再每次執行一個比較大的操作後,通過執行 mysql_reset_connection 将連接配接的資源初始化。連接配接會被恢複到剛剛建立時的狀态。注意:這個過程不需要重新連接配接或者重新做權限驗證.

查詢緩存:

連接配接建立完成後,你就可以執行select語句了。執行邏輯就會來到第二部:查詢緩存。

Mysql收到一個查詢請求後,會先到 緩存區檢視,之前是不是執行過這這句話。**之前執行過的語句以及其結果,可能會議key-value的對的形勢,被直接緩存在記憶體中。key是查詢的語句,value是查詢的結果。**如果你的查詢能夠直接在這個緩存中找到key.那麼這個value就會被直接傳回個用戶端。

如果,語句不在查詢緩存中,就會繼續後面的執行階段。執行完成之後,執行接貨會被存入查詢緩存中。你可以看到,如果查詢命中緩存。Mysql不需要執行就免的複雜操作,就可以執行效率很高。

但是大多數情況下,建不要使用查詢緩存,為什麼?因為查詢緩存往往弊大于利。

查詢緩存的失效非常頻繁,隻要有對一個表的更新,這個表上所有的查詢緩存,都會被清空。 是以和可能,你費勁的把結構儲存起來,還沒有使用呢,就被一個更新全部清空了。對于更新壓力大的資料庫來說,查詢緩存命中的機率,會非常的低。除非你的業務,就是有一張靜态表,很長時間才會更新一次。比如一個系統配置表。這張表适合使用查詢緩存。

需要注意的是,查詢緩存,整塊功能,全部删掉了,也就是說8.0開始,徹底沒有這個功能了。

分析器

如果命中緩存,沒有成功,就要開始真正的執行查詢語句了。首先Mysql需要知道你要做什麼?是以需要對sql語句做解析。

分析器先回做“詞法分析”。你輸入的是由多個字元串和空格,組合而成的一個sql語句。資料庫需要識别出字元串分别是什麼,分别代表什麼。

mysql從你輸入的“select”這個關鍵字,識别出來,這是一個查詢語句。要把字元串 “table”識别成 “表明table”。把字元串ID,識别成列ID。

昨晚這些判斷以後,就要做"文法分析"。詞法分析器,會根據文法規則,判斷,你輸入的這sql語句是否滿足mysql的文法。如果你的語句不對,就會收到提示: you have an error in your sql syntax。提示的内容,為第一個出錯的地方。

優化器:

經過了分析器,mysql知道你要做什麼了。在開始執行之前,還要先經過優化器的處理。優化器是表裡面有多個索引的時候,決定各個表的連接配接順序。

比如: select * from table1 join table2 using(ID) where table1.c = 100 and table2.d = 300;

先可以從表1中取出 c列的取值為10的記錄,在根據ID值,關聯到表table2。再判斷table2 裡面 d的值,是否等于20。

也可以先從表 table2取出d = 300的記錄的id值。再根據ID值關聯到t1,再判斷t1裡面的c值,是否等于10。

這兩種執行方法的邏輯結果是一樣的。但是執行的效率會有不同,而優化器的左右就是決定選擇使用哪一個方案。

優化器階段完成後,這個語句的執行方案就确定下倆了,然後進入執行器階段。

執行器

執行器在執行之前,會先判斷一下你對這個表table有沒有執行查詢的權限,如果沒喲,就傳回沒有權限的錯誤

如下所示(在工程實作上,如果命中查詢緩存,會在查詢緩存傳回結果的時候,做權限驗證。)

如果有權限,就打開表,繼續執行。打開表的時候,執行求就會根據表的引擎定義。去使用引擎提供的接口。比如我們這個例子中的表Table1中,ID字段,沒有索引。那麼執行器的流程是這樣的:

[1]調用Innodb引擎接口取這個表的第一行,判斷ID值,是不是10.如果不是則跳過,如果是,則講這行的運作結果。存在結果集中。

[2]調用引擎接口取 下一行 重複相同的判斷擴及,知道管道這個表的最後一行。

[3]執行器将上述周遊過程中所有滿足條件的行,組成的記錄集作為結果集傳回給用戶端。

至此,這個語句就執行完了。

對于有所因的表,執行的邏輯也差不多。第一次調用的是“取出滿足條件的第一行”,之後,循環取“滿足條件的下一行”這個接口,這些接口都是引擎中已經定義好的 。

你會在查詢庫的慢查詢日志中,看到一個rows_examindex的字段,表示這個語句執行過程中,掃描了多少行。這個值就是在執行器,每次調用引擎擷取資料行的時候,累加的。

在很多場景下。執行器調用一次。在引擎内初,掃描了很多行。是以引擎掃描行數跟rows_examindex并不是完全相同的。我們後面,會專門有一篇文章,來講存儲引擎的内部機制,裡面會有詳細的說明。

小結

一條sql語句執行的時候,會先去建立連接配接、查詢緩存、分析器、優化器、**“執行器”**五個階段。

建立連接配接完成,在換緩存查詢不到資訊,就會真正的執行mysql語句,經過,分析器,優化器,執行器,将最終的結果傳回去。

OKR