01. MySQL基礎架構
SQL語句是如何執行的
學習一下mysql的基礎架構,從一條sql語句是如何執行的來學習。
一般我們寫一條查詢語句類似下面這樣:
select user,password from mysql.user;
這樣就可以返回一個結果,但卻不知這條語句的內部執行流程。
如下是mysql的邏輯架構圖:

Mysql可以分為Server層和存儲引擎層二部分。
Server層有連接器/緩存/分析器/優化器/執行器,涵蓋了mysql的很多核心功能。
存儲引擎層負責數據的存儲和讀取,支持Innodb,MyIsam,Memory,BlackHole等,Mysql5.5版本后默認的存儲引擎是Innodb。
接下來我們一層一層來看SQL語句的執行過程。
1)連接器
首先客戶端連接mysql時就是連接到了連接器上,連接器負責跟客戶端建立連接/校驗用戶身份,獲取權限。連接命令一般如下:
mysql -h ip地址 -P 端口 -u 用戶 -p
當客戶端輸入完了用戶名和密碼開始連接時,連接器會校驗:
- 如果用戶名或者密碼不正確,客戶端會收到一個“Access denied for user”的錯誤。
- 如果用戶名和密碼校驗正確,連接器會檢查用戶所擁有的權限。之后,這個連接里的權限邏輯判斷,都依賴此時讀到的權限。
這就意味著一個用戶成功建立連接之后,即使你用管理員把這個用戶的權限更改了,也是不會影響到已經連接的這個用戶,除非這個用戶斷開重新連接。讓連接器重新讀取權限才可以。
2)查詢緩存
連接建立成功之后,你就能夠執行select等語句了,這時就會進行第二步:查詢緩存
Mysql收到一個sql請求之后,先檢查緩存,看看之前是不是有執行過。如果執行過并緩存沒有過期,結果會以key-value的形式存儲在內存中,key是查詢語句,value是查詢結果。如果有緩存,直接把對應的value返回給客戶端。
如果語句不在查詢緩存中,就會向下執行下面的階段,執行完成后,會把結果放到緩存中。
查詢緩存的失效很平凡,因為只要更新一個表,那么這個表的所有查詢緩存結果都會被清空,所以對經常變更的表,查詢緩存的命中率很低。除非這個表數據比較穩定,不經常改變,才適合查詢緩存。
了解下:Mysql8.0版本之后,查詢緩存的功能就被刪了。

3)分析器
如果沒用命中緩存,分析器就開始工作了,對sql語句進行解析。
首先分析器會做“詞法分析”,你輸入的多個字符加上空格組成的sql語句,分析器需要分析出來里面字符分別都代表什么。
如從你輸入的"select"關鍵字開始,mysql知道這是一個查詢語句,然后分析出那個是表名,那個是你輸入的條件等等。
做完了詞法分析,開始做“語法分析”,根據詞法分析的結果,語法分析會判斷你輸入的這條sql語句是否符合Mysql語法。
如果你的語句不對,就會收到“You have an error in you SQL syntax”的錯誤提醒,如果下面這個語句select少打了開頭的字母“s”。
mysql> elect * from stu; ERROR 1064 (42000): You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near 'elect * from stu' at line 1
一般語法錯誤會提示第一個出現錯誤的位置,所以你要關注的是緊接著“use near”后面的內容。
4)優化器
經過了分析器,Mysql已經知道你要做什么了,在開始執行之前,還需要經過優化器的處理。
優化器是在表里面有多個索引的時候,決定使用哪個索引;或者在一個語句有多表關聯的時候,決定各個表的連接順序。
5)執行器
Mysql通過分析器知道了你要做什么,通過優化器知道了如何做,接下來就是執行器開始執行語句;
開始執行之前, 會先判斷你對要操作的表或庫有沒有權限,如果沒有就返回權限的錯誤。
如果有權限,就打開表繼續執行。打開表的時候,執行器會根據表的引擎定義,去使用這個引擎提供的接口。
比如這個select語句:select * from db1 where ID=100;
- 先調用Inodb引擎接口獲取表的第一行,判斷ID值是不是100,如果不是則跳過,如果是則將結果存在結果集中;
- 調用引擎接口獲取“下一行”,重復相同的判斷邏輯,直到讀取這個表的最后一行。
- 執行器將上述遍歷過程所有符合要求的結果返回給客戶端。
至此,這個select語句算是執行完了。
數據庫的慢查詢日志中會看到rows_examined的字段,表示這個語句執行過程中掃描了多少行。這個值就是在執行器每次調用引擎獲取數據行的時候累加的。
有些情況下,執行器調用一次,在引擎內部則掃描了多行,因此引擎掃描行數跟rows_examined并不完全相同。
這樣Mysql的邏輯架構和流程過了一遍,我也對整個sql語句的執行過程的各個階段有了一個初步的認識。也希望能對大家有幫助。