Mysql架構
一條SQL查詢語句是如何執行的?
Mysql基礎架構圖
mysql架構關系
service層:
連接器:管理鏈接 驗證權限 連接器會直接鏈接到緩存以及分析器
查詢緩存: 緩存中命中則直接返回
分析器:混村未能命中的時候 使用分析器 分析詞法 語法
優化器: 執行計划生成 索引選擇數據
執行器: 鏈接引擎操作數據
引擎層:
Innodb
Myisam
。。。
Service層
Server層包括連接器、查詢緩存、分析器、優化器、執行器等,涵蓋MySQL的大多數核心服務功能
涵蓋所有的函數功能: 日期 時間 數學 字符串
跨存儲引擎的功能: 存儲過程 觸發器 視圖
不同的存儲引擎共用一個service層
存儲引擎層
負責數據的存取
插件模式支持不同的存儲引擎
默認使用 innodb 引擎
按查詢過程了解各個組件的作用
1 連接器 管理數據庫鏈接 權限驗證
連接語句:mysql -h$ip -P$port -u$user -p
A 連接命令中的mysql是客戶端工具,用來跟服務端建立連接
B 完成TCP握手后,連接器就開始認證身份,輸入用戶名和密碼
如果用戶名或密碼不對,你就會收到一個"Access denied for user"的錯誤,然后客戶端程序結束執行。
如果用戶名密碼認證通過,連接器會到權限表里面查出你擁有的權限。之后,這個連接里面的權限判斷邏輯,都將依賴於此時讀到的權限
即一個用戶成功建立連接后,即使你用管理員賬號對這個用戶的權限做了修改,也不會影響已經存在連接的權限。修改完成后,只有再新建的連接才會使用新的權限設置
客戶端如果太長時間沒動靜,連接器就會自動將它斷開。這個時間是由參數wait_timeout控制的,默認值是8小時
關於數據庫的鏈接
長連接:連接成功后,如果客戶端持續有請求,則一直使用同一個連接
短鏈接:每次執行完很少的幾次查詢就斷開連接,下次查詢再重新建立一個
鏈接的建立過程復雜,操作中如果需要大量長時間的存取數據 使用長鏈接
使用長鏈接的缺點:
容易占用內存, 因為MySQL在執行過程中臨時使用的內存是管理在連接對象里面的。這些資源會在連接斷開的時候才釋放。所以如果長連接累積下來,可能導致內存占用太大,被系統強行殺掉(OOM)
導致:從現象看就是MySQL異常重啟了
解決長連接占用內存,短鏈接繁瑣的問題
-
定期斷開長連接。使用一段時間,或者程序里面判斷執行過一個占用內存的大查詢后,斷開連接,之后要查詢再重連。
-
如果你用的是MySQL 5.7或更新版本,可以在每次執行一個比較大的操作后,通過執行 mysql_reset_connection來重新初始化連接資源。這個過程不需要重連和重新做權限驗證,但是會將連接恢復到剛剛創建完時的狀態。
2 查詢緩存 命中查詢就返回 否進則分析查詢
建立連接后開始第二步驟:查詢
MySQL拿到一個查詢請求后,會先到查詢緩存看看,之前是不是執行過這條語句。
之前執行過的語句及其結果可能會以key-value對的形式,被直接緩存在內存中。
key是查詢的語句,
value是查詢的結果。
如果你的查詢能夠直接在這個緩存中找到key,那么這個value就會被直接返回給客戶端
如果查詢不在就會繼續后面的執行階段。執行完成后,執行結果會被存入查詢緩存中。這樣會大大提高查詢效率
查詢緩存的缺點
建立的查詢緩存容易被數據表更新所清空,對於頻繁更新數據的更不適合使用查詢緩存
對於靜態表,則可以使用查詢緩存 提高查詢速度
3 分析器
在第二步中,查詢如果沒有命中緩存,就會進入分析器,開始真正執行語句
首先,。Mysql要理解你的操作,因此,便使用分析器對查詢語句進行分析
分析器分析識別
詞法分析:識別關鍵字
分析器先會做"詞法分析"。你輸入的是由多個字符串和空格組成的一條SQL語句,MySQL需要識別出里面的字符串分別是什么,代表什么。
MySQL從你輸入的"select"這個關鍵字識別出來,這是一個查詢語句。它也要把字符串"T"識別成"表名T",把字符串"ID"識別成"列ID"
語法分析:判斷語法
根據詞法分析的結果,語法分析器會根據語法規則,判斷你輸入的這個SQL語句是否滿足MySQL語法
如果語法不對,就會收到報錯提醒,一般語法錯誤會提示第一個出現錯誤的位置
即關注報錯中的 use near
4 優化器
經過分析器的分析,mysql就知道你要做的事情是什么了
但是,在開始執行之前,需要經過優化器的處理。
優化器是在表里面有多個索引的時候,決定使用哪個索引;或者在一個語句有多表關聯(join)的時候,決定各個表的連接順序。比如你執行下面這樣的語句,這個語句是執行兩個表的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。
這兩種執行方法的邏輯結果是一樣的,但是執行的效率會有不同,而優化器的作用就是決定選擇使用哪一個方案
目前的筆記任然是全局了解的狀態,因此對於優化器的具體內容,會有具體的篇章
5 執行器
經過優化器篩選優化的查詢語句后,就進入執行器階段,開始執行語句
執行步驟
1 判斷權限
開始執行的時候,要先判斷一下你對這個表T有沒有執行查詢的權限,如果沒有,就會返回沒有權限的錯誤,如下所示。
mysql> select * from T where ID=10;
ERROR 1142 (42000): SELECT command denied to user 'b'@'localhost' for table 'T'
如果有權限,就打開表繼續執行。打開表的時候,執行器就會根據表的引擎定義,去使用這個引擎提供的接口。
比如我們這個例子中的表T中,ID字段沒有索引,那么執行器的執行流程是這樣的:
-
調用InnoDB引擎接口取這個表的第一行,判斷ID值是不是10,如果不是則跳過,如果是則將這行存在結果集中;
-
調用引擎接口取"下一行",重復相同的判斷邏輯,直到取到這個表的最后一行。
-
執行器將上述遍歷過程中所有滿足條件的行組成的記錄集作為結果集返回給客戶端。
至此,這個語句就執行完成了。
對於有索引的表,執行的邏輯也差不多。第一次調用的是"取滿足條件的第一行"這個接口,之后循環取"滿足條件的下一行"這個接口,這些接口都是引擎中已經定義好的。
你會在數據庫的慢查詢日志中看到一個rows_examined的字段,表示這個語句執行過程中掃描了多少行。這個值就是在執行器每次調用引擎獲取數據行的時候累加的。
在有些場景下,執行器調用一次,在引擎內部則掃描了多行,因此引擎掃描行數跟rows_examined並不是完全相同的