整體框架

MySQL 可以分為 Server 層和存儲引擎層(Storage Engines)兩部分
Server 層
Server 層包括連接器、查詢緩存、分析器、優(yōu)化器、執(zhí)行器等,涵蓋了Mysql的大多數核心服務功能,以及內置函數,存儲過程,觸發(fā)器,試圖等(所有的跨存儲以前寧的操作)
Storage Engines層
主要是負責數據的存儲和提取,其架構模式是插件式的,支持InnoDB,MyISAM,Memory等多個存儲引擎。InnoDB是最常用的,也是Mysql5.5.5版本開始成為默認的存儲引擎
連接器
- 負責維護客戶端的鏈接,獲取權限,管理鏈接
- 如果你沒有后續(xù)的動作,這個連接就處于空閑狀態(tài)(show processlist查看所有鏈接)
- 客戶端如果太長時間沒動靜,連接器就會自動將它斷開。這個時間是wait_timeout來控制的,默認8小時
- 短鏈接:每次完成執(zhí)行都斷開鏈接(建立鏈接的過程比較耗時,建議盡量使用長鏈接)
- 長連接:客戶端維持請求一直使用一個鏈接(但是全部使用長鏈接會導致內存使用過快)
- 解決長鏈接內存過大的問題:Mysql5.7之后,可以每次執(zhí)行一個較大的操作后,執(zhí)行mysql_reset_connection開重新初始化鏈接資源,此過程無需重連和權限校驗
查詢緩存
MYSQL查詢一個請求會先看查詢緩存是否存在,之前執(zhí)行過的緩存會已KV的形式存儲在內存中,如果有則直接返回,但是默認建議不開啟查詢緩存,因為查詢緩存失效頻率太高,只要對一個表進行更新,那么這個表上所有的查詢緩存都會被清空。mysql8.0已經將查詢緩存整個刪除了
分析器
分析器分析SQL語句進行語法分析,如果判斷語法不對則會返回"You have an error in your SQL syntax" 的錯誤提醒
優(yōu)化器
在經過分析器判斷語法正確后,需要通過優(yōu)化器進行優(yōu)化處理,優(yōu)化器是在表中存在多個索引的時候,決定使用哪個索引,或者在一個語句有多表關聯查詢(join)的時候決定表的鏈接順序
執(zhí)行器
用于語句執(zhí)行
- 先判斷你有沒有這個表的執(zhí)行查詢的權限,沒有返回權限錯誤的信息
- 根據引擎提供額執(zhí)行接口執(zhí)行語句查詢
常用引擎,區(qū)別對比
| 引擎 | Innodb | Myisam |
|---|---|---|
| 存儲文件 | .frm 表定義文件 .ibd 數據文件 |
.frm 表定義文件 .myd 數據文件 .myi索引文件 |
| 鎖表 | 表鎖、行鎖 | 表鎖 |
| 事物 | ACID | 不支持 |
| CRUD | 讀、寫 | 讀多 |
| count | 掃表 | 專門存儲的地方 |
| 索引結構 | B+Tree(聚集索引) | B+Tree(非聚集索引) |
| 版本默認 | 5.7版本之后的默認引擎 | 5.7版本之前的默認引擎 |
一條查詢語句是如何執(zhí)行的
上述MYSQL各個模塊的順序就是一條查詢語句的執(zhí)行順序
- 連接器創(chuàng)建客戶端與服務器之間的鏈接
- 首先查詢是否有查詢緩存如果有則直接使用
- 如果沒有查詢緩存則到達分析器進行SQL語句的語法分析
- 確認語法無誤之后,通過優(yōu)化器進行查詢優(yōu)化
5.最終通過執(zhí)行器調用引擎執(zhí)行查詢
一條更新語句是如何執(zhí)行的
1.將ID為2的一條數據+1
- 執(zhí)行器查詢ID = 2的之一行,ID是逐漸,引擎使用B樹搜索找到這一行,如果ID=2這一行數據在內存中(change buffer中),則直接返回給執(zhí)行器,否則需要從磁盤讀取到內存中。
- 執(zhí)行器拿到行數據進行+1操作。再調用引擎寫入新數據
- 引擎將這行數據更新到內存中,同時將這個數據記錄到redo log中,此時redo log 處于prepare狀態(tài)。然后告知執(zhí)行器完成,隨時可以提交數據
5.執(zhí)行器生成操作的binlog,并把binlog寫入磁盤
6.執(zhí)行器調用引擎的提交事務接口,引擎把剛剛寫入的redo log改成提交狀態(tài)更新完成
過程中涉及到的幾個角色,主要是涉及到redo log(重做日志)和 binlog(歸檔日志)這兩個模塊
redo log
如果每一次的更新操作都需要寫進磁盤,然后磁盤也要找到對應的那條記錄,然后更新,整個過程IO成本過高,為了解決上述問題,可以通過WAL技術來實現(Write-Ahead Logging),原理是,當有一條更新記錄的時候,innodb先將操作記錄到redo log中,并更新內存change buffer ,這個時候更新就完成了,然后Innodb會在是到的時候將操作記錄更新到磁盤中,往往是系統比較空閑,或者change buffer 寫滿,或者redo log寫滿的時候
- redo log 是[固定大小的,一組四個文件,每個文件1G大小
- 有了redo log,innodb可以保證數據庫異常數據也不丟失,保證了數據的原子性
binlog
上述說的redo log是innodb引擎特有的,而binlog則是Server層自己的日志,又稱歸檔日志。為什么有兩個日志,因為MYSQL之前沒有innodb引擎。而且binlog只用于歸檔。他們有一下不同
- redo log是innodb特有的,而binlog是mysql的server層實現的,所有引擎都可以使用
- redo log 是物理日志,記錄數據也上做了什么修改 ,binlog是邏輯日志,記錄這個語句的原始邏輯"比如給ID=2 這一行的c字段加一"
- redo log 是循環(huán)寫的,空間固定用完會刷新到磁盤,而binlog是最追加寫入的
