一條 SQL 語句是如何執行的

1. select 語句執行過程

image-20221011144626201

一條 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 的操作。從頭開始寫,寫到末尾就又回到開頭循環寫,如下面這個圖所示。

image-20221011154306520

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

  1. 執行器先找引擎取 ID=2 這一行。ID 是主鍵,引擎直接用樹搜索找到這一行。如果 ID=2 這一行所在的數據頁本來就在內存中,就直接返回給執行器;否則,需要先從磁盤讀入內存,然後再返回。
  2. 執行器拿到引擎給的行數據,把這個值修改成張三
  3. 引擎將這行新數據更新到內存中,同時將這個更新操作記錄到 redo log 裏面,此時 redo log 處於 prepare 狀態。然後告知執行器執行完成了,隨時可以提交事務。
  4. 執行器生成這個操作的 binlog,並把 binlog 寫入磁盤。
  5. 執行器調用引擎的提交事務接口,引擎把剛剛寫入的 redo log 改成提交(commit)狀態,更新完成。

兩階段提交就是先提交 redolog,然後寫入 binlog,binlog 寫入成功後再提交 redolog

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章