1. select 語句執行過程
一條 select 語句的執行過程如上圖所示
1、建立連接
連接器會校驗你輸入的用戶名和密碼是否正確,如果錯誤會返回提示,如果正確,連接器會查詢當前用戶對於的權限。連接器的作用就是校驗用戶權限
2、查詢緩存
MySQL 中有個緩存的概念,當你在執行一條 SQL 查詢語句時,MySQL 會先去緩存中查看是否有對應的記錄,如果有,則直接返回,如果沒有,則取數據庫中查詢,查詢完成後再放入緩存中。這個查詢緩存的目的是爲了加快 MySQL 查詢速度。
這裏建議你將這個緩存的選項關閉上,因爲在實際項目中,這個查詢緩存用處不大,爲什麼這麼說。因爲當有 update、或者 delete 語句執行時,這張的表查詢緩存就會失效,下次查詢還是需要從數據庫中查詢,所以通常來說查詢緩存並不能提高性能。
3、分析器
分析器作用是進行詞法分析,語法分析。對於 select 語句而言,MySQL 拿到這條 SQL 語句後,識別出 select 關鍵詞,知道這是一條查詢語句,然後再取識別 from 以及表名,識別字段,這個步驟是詞法分析。詞法分析完成後還需要進行語法分析,也就是判斷這條語句的語法是否正確,比如你 select 寫成了 selct,那麼語法分析就會檢驗出來
4、優化器
優化器職責是對 sql 語句進行優化,比如這條語句該用什麼索引,sql 順序需不需要調整。
5、執行器
經過上面幾部分析,就來到了執行器,開始從數據庫查詢數據了。查詢數據前會校驗一下有無權限該表的權限,如果沒有則返回錯誤提示。有權限則開始掃描行,查看是否滿足條件,滿足條件的結果放入結果集中。
2. update 語句執行過程
update 語句執行過程和 select 語句相同,也需要經過連接、分析器、優化器、執行器這些步驟。不同的是,在 update 執行過程中涉及到兩個日誌,一個是 redo log,一個是 binlog
redo log
首先需要明確的是,redo log 是 Inndb 存儲引擎獨有的,其他引擎沒有。redo log 主要作用是記賬
舉個通俗易懂的例子,你是掌櫃的,開了一家店鋪,店鋪生意很好,每天都有很多人來,有些人都是常客,喫飯都是月結,於是你有一個賬本,賬本上記錄了誰欠你多少錢,店鋪剛開張時,客人少,你一筆筆記錄,沒問題,後來客人多了,你發現賬本查找起來很費時,影響效率,於是你找了一個黑板,客人來了以後,消費了多少錢,你就記在黑板上,等到不忙的時候在彙總到賬本上。
這裏的黑板就是 redo log,賬本就是 MySQL 數據庫磁盤,這麼做的原因是爲了提高效率,不然 MySQL 每一次操作都要寫入到磁盤中,效率很低,有了 redo log 以後,每次 update 操作,我只需要寫到內存上,然後記錄到 redo log 中即可返回,這樣速度快了很多。等到空閒的時候,再將 redo log 中的數據寫入到磁盤中進行持久化。
InnoDB 的 redo log 是固定大小的,比如可以配置爲一組 4 個文件,每個文件的大小是 1GB,那麼這塊“粉板”總共就可以記錄 4GB 的操作。從頭開始寫,寫到末尾就又回到開頭循環寫,如下面這個圖所示。
write pos 是當前記錄的位置,一邊寫一邊後移,寫到第 3 號文件末尾後就回到 0 號文件開頭。checkpoint 是當前要擦除的位置,也是往後推移並且循環的,擦除記錄前要把記錄更新到數據文件。
write pos 和 checkpoint 之間的是“粉板”上還空着的部分,可以用來記錄新的操作。如果 write pos 追上 checkpoint,表示“粉板”滿了,這時候不能再執行新的更新,得停下來先擦掉一些記錄,把 checkpoint 推進一下。
有了 redo log,InnoDB 就可以保證即使數據庫發生異常重啓,之前提交的記錄都不會丟失,這個能力稱爲crash-safe。
要理解 crash-safe 這個概念,可以想想我們前面賒賬記錄的例子。只要賒賬記錄記在了粉板上或寫在了賬本上,之後即使掌櫃忘記了,比如突然停業幾天,恢復生意後依然可以通過賬本和粉板上的數據明確賒賬賬目。
binlog
上面說的 redo log 是引擎層的日誌,那麼 binlog 則是 MySQL Server 層的日誌
binlog 主要是記錄 MySQL 的原始操作語句,比如 update user set name = "張三" where id = 2,binlog 就將它記錄下來
binlog 和 redolog 區別
- redolog 是引擎層面的日誌,是 Inndb 獨有的,binlog 是 Server 層的,所有引擎都可以使用
- redo log 是物理日誌,記錄的是“在某個數據頁上做了什麼修改”;binlog 是邏輯日誌,記錄的是這個語句的原始邏輯,比如“給 ID=2 這一行的 c 字段加 1 ”。
- redo log 是循環寫的,空間固定會用完;binlog 是可以追加寫入的。“追加寫”是指 binlog 文件寫到一定大小後會切換到下一個,並不會覆蓋以前的日誌。
兩階段提交
update 語句執行的內部流程
update user set name = "張三" where id = 2
- 執行器先找引擎取 ID=2 這一行。ID 是主鍵,引擎直接用樹搜索找到這一行。如果 ID=2 這一行所在的數據頁本來就在內存中,就直接返回給執行器;否則,需要先從磁盤讀入內存,然後再返回。
- 執行器拿到引擎給的行數據,把這個值修改成張三
- 引擎將這行新數據更新到內存中,同時將這個更新操作記錄到 redo log 裏面,此時 redo log 處於 prepare 狀態。然後告知執行器執行完成了,隨時可以提交事務。
- 執行器生成這個操作的 binlog,並把 binlog 寫入磁盤。
- 執行器調用引擎的提交事務接口,引擎把剛剛寫入的 redo log 改成提交(commit)狀態,更新完成。
兩階段提交就是先提交 redolog,然後寫入 binlog,binlog 寫入成功後再提交 redolog