從 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異常重啓了。
怎麼解決這個問題呢?你能夠考慮如下兩種方案。
mysql_reset_connection
來從新初始化鏈接資源。這個過程不須要重連和從新作權限驗證,可是會將鏈接恢復到剛剛建立完時的狀態。鏈接完成後,你就能夠執行 SQL 語句了,這行邏輯就會來到第二步:查詢緩存。
MySQL 在獲得一個執行請求後,會首先去 查詢緩存 中查找,是否執行過這條 SQL 語句,以前執行過的語句以及結果會以 key-value 對的形式,被直接放在內存中。key 是查詢語句,value 是查詢的結果。若是經過 key 可以查找到這條 SQL 語句,就直接返回 SQL 的執行結果。
若是語句不在查詢緩存中,就會繼續後面的執行階段。執行完成後,執行結果就會被放入查詢緩存中。能夠看到,若是查詢命中緩存,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;
這兩種執行方法的邏輯結果是同樣的,可是執行的效率會有不一樣,而優化器的做用就是決定選擇使用哪個方案。
優化器會判斷你使用了哪一種索引,使用了何種鏈接,肯定效率最高的執行方案。
MySQL 經過分析器知道了你的 SQL 語句是否合法,你想要作什麼操做,經過優化器知道了該怎麼作效率最高,而後就進入了執行階段,開始執行這條 SQL 語句。
開始執行的時候,MySQL 首先會判斷你對要操做的表有沒有執行這條語句的權限。
ERROR 1142 (42000): SELECT command denied to user 'foo'@'localhost' for table 'bar'
)。打開表的時候,執行器就會根據表的引擎定義,去使用這個引擎提供的接口查詢數據返回給客戶端。
至此,MySQL 對於一條語句的執行過程也就完成了。
參考《MySQL實戰45講》丁奇