- MySQL的邏輯架構圖;
MySQL 大體分為 “server 層” 和 “存儲引擎層” 兩部分;
Server 層
包括 連接器、查詢緩存、分析器、優化器、執行器 等,涵蓋MySQL的大多數核心服務
功能,以及所有的內置函數(日期,時間,數學,加密函數等),所有誇存儲引擎的功能都可以
在這一層實現,例如:存儲過程,觸發器,視圖等;
存儲引擎層
負責數據的存儲和提取,使用插件式的架構模式;支持 InnoDB、MyISAM、Memory 等多個存儲引擎
現在最常用的存儲引擎是 InnoDB ,從MySQL 5.5.5 版本開始 InnoDB 是默認存儲引擎。
連接器
連接器負責跟客戶端建立連接,獲取權限,維持和管理連接;一般寫法如下:
mysql -h 192.168.5.116 -P 3306 -u root -p123456
在完成經典的TCP三次握手之后,MySQL就會根據提供的憑證來驗證用戶身份,若驗證失敗則會收到
一個"Access denied for user"的錯誤,然后客戶端程序執行結束;若驗證通過 連接器會到權限表中獲取
你所擁有的操作權限;之后這個連接里權限判斷邏輯都依賴於此時讀取的權限;若此時管理員對這個用
戶的權限做了修改,也不會影響已經存在連接的權限,修改完成后,只有下次新建連接才會使用新的權限;
連接完成后若沒有后續操作,則該鏈接成為空閑連接,可以使用 show processlist 命令 查看;客戶端若
太長時間沒有后續操作,連接器會自動斷開該連接,這個時間是由參數:wait_timeout 控制的,默認8小時;huo
若斷開連接后,客戶端繼續請求的話:則會收到一個錯誤提示(Lost connection to MySQL server during query)
這時候如果要繼續則需要重新連接MySQL;
數據庫中,長連接是指:連接成功后,客戶端持續有請求則一直使用同一個連接;短連接則是指:每次執行完
很少的幾次查詢就斷開連接,下次查詢就重新建立連接;
新建連接的過程比較復雜,所以在使用過程中盡量減少建立連接的動作,也就是盡量使用長連接;
但是全部使用長連接之后,可能會導致MySQL占用內存會漲的很快,這是因為MySQL在執行過程中臨時使用的
內存是管理在連接對象里的,這些資源會在連接斷開的時候才會釋放;所以長時間累積下來 可能導致內存占用
過大而被系統強殺(OOM);從現象看就是MySQL異常重啟了。
解決該問題可考慮一下倆方案:
- 定期斷開長連接:使用一段時間,或者程序里面判斷執行過一個占用內存大的查詢后,斷開連接,之后重新連接;
- 若你的MySQL版本是 5.7 及以上 可以再每次執行一個較大的操作后,通過執行 “
mysql_reset_connection”來重新
初始化鏈接資源這個時候不需要重新連接和重新驗證權限但是會將連接恢復到剛剛創建連接的狀態
查詢緩存
MySQL 拿到一個查詢請求后會到查詢緩存中看看之前有沒有執行過這條查詢語句,(之前執行過的語句會以 key-value 的形式直接緩存在內存中,key 是查詢語句,value 是查詢結果);
如果這個查詢語句(key)恰巧在緩存中,查詢緩存會直接將這個key的value返回給客戶端;如果查詢語句不在緩存中就會繼續后面的執行階段,執行完成后執行結果會存入查詢緩存中;
“查詢緩存的失效非常頻繁”,只要對某個表進行過更新操作那么這個表的所有查詢緩存都會清空,因此不建議使用查詢緩存,況且 MySQL 8.0 版本直接將查詢緩存干掉了 :(
分析器
沒有命中查詢緩存則該真正執行查詢語句了
首先分析器會先做 ‘詞法分析’ 分析SQL語句字符串中的關鍵字,是select還是insert等等,做完詞法分析后就開始語法分析;根據詞法分析的結果 語法分析器會根據語法規則判斷SQL語句是否滿足MySQL的語法。
優化器
經過分析器后MySQL就知道了這條SQL語句要干什么了,在開始執行之前還要經過優化器的處理;
優化器是在表里有多個索引的時候決定使用哪個索引,或者一個語句有多表關聯(join)的時候,決定各個表的連接順序;
例如:
mysql> select * from t1 join t2 using(ID) where t1.c=10 and t2.d=20;
- 既可以先從表 t1 里面取出 c=10 的記錄的 ID 值,再根據 ID 值關聯到表 t2,再判斷 t2 里面 d 的值是否等於 20。
- 也可以先從表 t2 里面取出 d=20 的記錄的 ID 值,再根據 ID 值關聯到 t1,再判斷 t1 里面 c 的值是否等於 10。
這兩種方法的結果是一樣的,但執行的效率不同,而優化器的作用就是決定執行那種方案。
執行器
SQL語句經過了前面的流程,MySQL就知道了要做什么,該怎么做,接下來就要做了:
首先執行器會判斷當前用戶對這張表有沒有響應的操作權限,若沒有就會返回沒有權限的錯誤(若查詢緩存命中了,會先判斷權限),有權限則打開表繼續執行;
打開表的時候執行器會根據表的引擎定義去使用這個引擎提供的接口;
例如:
mysql> select * from T where ID=8;
比如我們這個例子中的表 T 中,ID 字段沒有索引,那么執行器的執行流程是這樣的:
- 調用 InnoDB 引擎接口取這個表的第一行,判斷 ID 值是不是 10,如果不是則跳過,如果是則將這行存在結果集中;
- 調用引擎接口取“下一行”,重復相同的判斷邏輯,直到取到這個表的最后一行。
- 執行器將上述遍歷過程中所有滿足條件的行組成的記錄集作為結果集返回給客戶端。
至此SQL語句執行完成。