MySQL邏輯架構 - SQL語句的執行都經歷了哪些步驟

MySQL邏輯架構 - SQL語句的執行都經歷了哪些步驟

從 MySQL 架構來理解,咱們能夠把 MySQL 拆解成幾個零件,以下圖所示mysql

MySQL 邏輯架構模型

大致來講,MySQL 能夠分爲 Server層存儲引擎層兩部分。sql

Server 層包括鏈接器、查詢緩存、分析器、優化器、執行器,涵蓋MySQL的大多數核心服務功能,以及全部的內置函數(如日期、時間、數學和加密函數等),全部跨存儲引擎的功能也在這一層實現,包括 存儲過程、觸發器、視圖等。數據庫

存儲引擎層負責數據的存儲和提取。包括 MySQL 常見的存儲引擎,包括 MyISAM、InnoDB 和 Memory 等,最經常使用的是 InnoDB,也是如今 MySQL 的默認存儲引擎。
存儲引擎也能夠在建立表的時候手動指定,使用以下語句:緩存

CREATE TABLE t (i INT) ENGINE = <Storage Engine>;

不一樣存儲引擎的表數據存取方式不一樣,支持的功能也不一樣。
從圖中能夠看出,不一樣的存儲引擎共用一個Server層,也就是從鏈接器到執行器的部分。架構

鏈接器

首先須要在 MySQL 客戶端登錄才能使用,因此須要一個鏈接器來鏈接用戶和 MySQL 數據庫,咱們通常是使用函數

mysql -h<host> -P<port> -u<用戶名> -p[<密碼>]

來進行 MySQL 登錄,和服務端創建鏈接。優化

雖然密碼能夠直接跟在 -p 後面寫在命令行中,但這樣可能會致使你的密碼泄露。強烈建議不輸入密碼,直接運行命令,而後再再交互對話框中輸入密碼。

在完成 TCP 握手 後,鏈接器會根據你輸入的用戶名和密碼驗證你的登陸身份。若是用戶名或者密碼錯誤,MySQL 就會提示 Access denied for user,而後客戶端程序結束執行。若是用戶名密碼認證經過,鏈接器會到權限表裏面查出你擁有的權限。以後,這個鏈接裏面的權限判斷邏輯,都將依賴於此時讀到的權限。加密

這就意味着,一個用戶成功創建鏈接後,即便你用管理員帳號對這個用戶的權限作了修改,也不會影響已經存在鏈接的權限。修改完成後,只有再新建的鏈接纔會使用新的權限設置。

鏈接完成後,若是沒有後續的動做,這個鏈接就處於空閒狀態,可使用 show processlist 命令中看到它。spa

mysql> show processlist;
+--------+-------------+---------------------+--------+---------+------+----------+------------------+
| Id     | User        | Host                | db     | Command | Time | State    | Info             |
+--------+-------------+---------------------+--------+---------+------+----------+------------------+
| 214416 | master      | 124.126.130.4:29734 | db_name | Sleep   |   13 |          | NULL             |
| 214417 | master      | 124.126.130.4:29754 | db_name | Query   |    0 | starting | show processlist |
+--------+-------------+---------------------+--------+---------+------+----------+------------------+
2 rows in set (0.07 sec)

其中的Command列顯示爲 Sleep 的這一行,就表示如今系統裏面有一個空閒鏈接。客戶端若是太長時間沒動靜,鏈接器就會自動將它斷開。這個時間是由參數 wait_timeout 控制的,默認值是8小時。命令行

若是在鏈接被斷開以後,客戶端再次發送請求的話,就會收到一個錯誤提醒: Lost connection to MySQL server during query。這時候若是你要繼續,就須要重連,而後再執行請求了。

數據庫裏面,長鏈接是指鏈接成功後,若是客戶端持續有請求,則一直使用同一個鏈接。短鏈接則是指每次執行完不多的幾回查詢就斷開鏈接,下次查詢再從新創建一個。

創建鏈接的過程一般是比較複雜的,因此建議在使用中要儘可能減小創建鏈接的動做,也就是儘可能使用長鏈接。

可是所有使用長鏈接後,你可能會發現,有些時候MySQL佔用內存漲得特別快,這是由於MySQL在執行過程當中臨時使用的內存是管理在鏈接對象裏面的。這些資源會在鏈接斷開的時候才釋放。因此若是長鏈接累積下來,可能致使內存佔用太大,被系統強行殺掉(OOM),從現象看就是MySQL異常重啓了。

怎麼解決這個問題呢?你能夠考慮如下兩種方案。

  1. 按期斷開長鏈接。使用一段時間,或者程序裏面判斷執行過一個佔用內存的大查詢後,斷開鏈接,以後要查詢再重連。
  2. 若是你用的是 MySQL 5.7 以上的版本,能夠在每次執行一個比較大的操做後,經過執行 mysql_reset_connection 來從新初始化鏈接資源。這個過程不須要重連和從新作權限驗證,可是會將鏈接恢復到剛剛建立完時的狀態。

查詢緩存

鏈接完成後,你就能夠執行 SQL 語句了,這行邏輯就會來到第二步:查詢緩存

MySQL 在獲得一個執行請求後,會首先去 查詢緩存 中查找,是否執行過這條 SQL 語句,以前執行過的語句以及結果會以 key-value 對的形式,被直接放在內存中。key 是查詢語句,value 是查詢的結果。若是經過 key 可以查找到這條 SQL 語句,就直接返回 SQL 的執行結果。

若是語句不在查詢緩存中,就會繼續後面的執行階段。執行完成後,執行結果就會被放入查詢緩存中。能夠看到,若是查詢命中緩存,MySQL 不須要執行後面的複雜操做,就能夠直接返回結果,效率會很高。

MySQL 查詢緩存流程圖

可是大多數狀況下,不建議使用查詢緩存
由於查詢緩存的失效很是頻繁,只要在 MySQL 中對某一張表執行了更新操做,那麼這張表上的全部的查詢緩存就會失效,對於更新頻繁的數據表來講,查詢緩存的命中率會很是低。除非你的業務就是有一張靜態表,很長時間纔會更新一次。好比,一個系統配置表,那這張表上的查詢才適合使用查詢緩存。

好在MySQL也提供了這種「按需使用」的方式。你能夠將參數 query_cache_type 設置成 DEMAND,這樣對於默認的SQL語句都不使用查詢緩存。而對於你肯定要使用查詢緩存的語句,能夠用 SQL_CACHE 顯式指定:

select SQL_CACHE * from T where ID=10;

須要注意的是,MySQL 8.0版本直接將查詢緩存的整塊功能刪掉了。

分析器

若是沒有命中查詢緩存,就要開始真正執行 SQL 語句了。
首先,MySQL 會根據你寫的 SQL 語句進行解析,分析器會先作 詞法分析,你輸入的是由多個字符串和空格組成的一條 SQL 語句,MySQL 須要識別出裏面的字符串是什麼,表明什麼。

而後進行 語法分析,根據詞法分析的結果, 語法分析器會根據語法規則,判斷你輸入的這個 SQL 語句是否知足 MySQL 語法。若是 SQL 語句不正確,就會提示 You have an error in your SQL syntax

優化器

通過分析器的詞法分析和語法分析後,這條 SQL 就合法了,MySQL 就知道你要作什麼了。可是在執行前,還須要通過優化器的處理。

優化器是在表裏面有多個索引的時候,決定使用哪一個索引;或者在一個語句有多表關聯(join)的時候,決定各個表的鏈接順序。好比你執行下面這樣的語句,這個語句是執行兩個表的join:

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。

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

優化器會判斷你使用了哪一種索引,使用了何種鏈接,肯定效率最高的執行方案。

執行器

MySQL 經過分析器知道了你的 SQL 語句是否合法,你想要作什麼操做,經過優化器知道了該怎麼作效率最高,而後就進入了執行階段,開始執行這條 SQL 語句。

開始執行的時候,MySQL 首先會判斷你對要操做的表有沒有執行這條語句的權限。

  • 若是沒有權限,就會返回沒有權限的錯誤(ERROR 1142 (42000): SELECT command denied to user 'foo'@'localhost' for table 'bar')。
  • 若是有權限,就打開表繼續執行。

打開表的時候,執行器就會根據表的引擎定義,去使用這個引擎提供的接口查詢數據返回給客戶端。

至此,MySQL 對於一條語句的執行過程也就完成了。

參考《MySQL實戰45講》丁奇
相關文章
相關標籤/搜索