一條select語句執行流程
第一步:聯結器
聯結器負責跟客戶端建立連線、獲取許可權、維持和管理連線。如果使用者名稱密碼驗證通過後,聯結器會到許可權表裡面查出你擁有的許可權。之後該連線的許可權驗證都依賴於剛查出來的許可權。
第二步:查詢快取
當獲取連線後,一條SELECT語句會先去查詢快取,看之前是否執行過。如果獲取到快取後就執行返回,不然繼續後面的步驟。
大多數時候不建議使用快取,因為只要一個表更新,這個表上的所有快取資料就會被清空了。對於那些經常更新的表來說,快取命中率很低。MYSQL8版本直接將查詢快取的整塊功能刪掉了。
第三步:分析器
分析器首先會做“詞法分析”,MYSQL會識別出SQL語句裡面的字串是什麼以及代表什麼。接下來就是“語法分析器”,分析SQL的語法問題。
第四步:優化器
優化器會對SQL的執行順序,使用哪個索引進行優化。確定SQL的執行方案。
第五步:執行器
執行器執行SQL語句會對許可權進行校驗,如果有許可權,就開啟表繼續執行。開啟表的時候,執行器就會根據表的引擎定義,去使用這個引擎提供的介面。
一條update語句執行流程
update語句除了會執行上面的五步,還會涉及兩個重要的日誌模組。
兩個重要的日誌模組
redo log (重做日誌)
redo log 是innodb所特有的,當有一條更新語句時,innoDB引擎會先把記錄寫到redo log中,然後更新記憶體,這時候更新就算完成了。innoDB會在合適的時候將這個記錄更新到磁碟中去。
特點:redo log 是固定大小的,屬於迴圈寫。redo log是物理日誌,記錄的是“在某個資料頁上做了什麼修改”。有了redo log ,InnoDB可以保證資料庫發生異常重啟的時候,之前提交的記錄不會丟失,這個能力為crash-safe。
binlog(歸檔日誌)
binlog屬於server層的日誌,是邏輯日誌,記錄的是這個語句的原始邏輯,比如給“id =1 的一行的某個欄位+2”。binlog是追加寫入的,binlog寫到一定的大小後切換到下一個,不會覆蓋之前的。
更新語句的內部流程
update t set n = n+2 where id =1
- 執行器先找引擎找到id=1的那一行,如果這一行的資料頁已經在記憶體中則直接返回給執行器。否則先從磁碟讀入記憶體中,然後在返回。
- 執行器拿到了引擎返回的資料行,把這個n值+1,得到新的行資料,然後調引擎的介面寫入這行新資料。
- 引擎將這行資料更新到記憶體中,同時將這個更新操作記錄到redo log裡,此時rodo log屬於prepare狀態。然後告知執行器執行完成了,隨時可以提交事務了。
- 執行器生成這個操作的binlog,並把binlog寫入磁碟。
- 執行器調引擎的提交事務介面,引擎把剛剛寫入的redo log的狀態改為commit狀態,更新完成。
兩段式提交
redo log的寫入分為兩部分,是為了保證這兩份日誌的邏輯一致。
相關配置
redo log 用於保證 crash-safe 能力。innodb_flush_log_at_trx_commit 這個引數設定成 1,表示每次事務的 redo log 都直接持久化到磁碟。
sync_binlog 這個引數設定成 1 的時候,表示每次事務的 binlog 都持久化到磁碟。