一條 Update 語句的執行過程是怎樣的?
前言
通過本文主要了解 Sql 執行流程,包括兩個問題:
-
1. MySQL 的一條 Select 語句是怎麼運行的
-
2. MySQL 的一條 Update 語句是怎麼運行的
先看第一個問題,這裏做個簡單描述 ,因爲我們着重還是看 Update
MySQL 執行一條 Select 語句是怎麼運行的?
這個問題大家在面試的時候大家都背過類似的題,而且網上也有很多答案,這裏分享一個大致流程介紹,關於下圖的介紹來自這裏 執行一條 select 語句,期間發生了什麼?。
-
• 連接器:建立連接,管理連接、校驗用戶身份;
-
• 查詢緩存:查詢語句如果命中查詢緩存則直接返回,否則繼續往下執行。MySQL 8.0 已刪除該模塊;
-
• 解析 SQL,通過解析器對 SQL 查詢語句進行詞法分析、語法分析,然後構建語法樹,方便後續模塊讀取表名、字段、語句類型;
-
• 執行 SQL:執行 SQL 共有三個階段:
-
• 預處理階段:檢查表或字段是否存在;將 select * 中的 * 符號擴展爲表上的所有列。
-
• 優化階段:基於查詢成本的考慮, 選擇查詢成本最小的執行計劃;
-
• 執行階段:根據執行計劃執行 SQL 查詢語句,從存儲引擎讀取記錄,返回給客戶端
相對於 Select,內容更多和更復雜的是 Update 語句的執行,接下來我們講展開細講,再看本文之前可以先看看之前的分享,這兩篇文章對 Double Write 和 Buffer Pool 有做詳細的介紹:
MySQL 的 Double Write 如何保證可靠性?
InnoDB 的 Buffer Pool 是如何管理數據頁的?
當然最好也瞭解下 redolog、undolog、binlog 的相關知識點,這塊知識我們會在後續繼續分享!
Update 執行邏輯
先把我畫的圖看完,圖中步驟比較多,需要花點時間看,你想我畫這個肯定花了更長時間,如果覺得還不錯的話,謝謝點贊收藏下,不足的話大家指正下!
執行流程圖
整個流程的架構很清晰:Client 客戶端、Server 層、InnoDB 引擎層、磁盤,這裏就不對每個組件的具體功能和細節處理做更詳細的解釋了,文章主要是幫我們把流程理清楚!
核心組成部分
當然這裏也涉及到幾個核心:Buffer Pool、Double Write、Redo Log、Undo Log、BinLog、WAL
Buffer Pool 和 Double Write 可以參考我之前的文章,在開頭就有分享原文鏈接,我們來看以下問題!
Redo Log、Undo Log、BinLog 分別存的什麼內容,分別是做什麼用的?
-
1. Redo Log 在引擎層實現,用來恢復數據的,保障已提交事務的持久化特性,記錄的是物理級別的數據頁 (包括 data page 和 undo page) 做的修改
-
2. Undo Log 在引擎層實現的邏輯日誌,用於數據回滾到之前狀態,對於每個 UPDATE 語句,對應一條相反的 UPDATE 的 undo log
-
3. BinLog 是 Server 實現的邏輯日誌,用於複製和恢復數據,記錄了所有的 DDL 和 DML 語句(除了數據查詢語句 select、show 等)
WAL 是什麼,哪裏用到了它?
WAL 全稱爲 Write-Ahead Logging,預寫日誌系統。主要寫 undo log、redo log、binlog 這些用到了。
真正使用 WAL 的原因是:磁盤的寫操作是隨機 IO,比較耗性能,所以如果把每一次的更新操作都先寫入 log 中,那麼就成了順序寫操作,實際更新操作由後臺線程再根據 log 異步寫入
UndoLog 會存儲在哪些地方?
我們從圖中也可以清晰的知道 UndoLog 在兩個地方:Buffer Pool 中的 undo page 頁,和磁盤中的表共享空間的 Undo log
詳解執行流程
看完執行流程圖大家都有個大概印象了,我們分三個部分進行更具體的文字化描述,一起來看看吧!
Client 客戶端:
- 1. 客戶端通過 tcp/ip 發送一條 sql 語句到 server 層
Server 層:
-
1. 接收客戶端過來的請求,進行權限驗證
-
2. 權限驗證通過後,解析器會對 SQL 語句進行詞法、語法分析等
-
3. 經過驗證解析的 SQL 語句會在優化器生成選擇最優執行計劃
-
4. 然後執行器將會執行經過優化的 SQL 語句
Server 層和存儲引擎之間怎麼通信的呢?
到這裏用戶發送的一個 SQL 已經經過各種驗證、分析、優化到了執行階段,那麼接下來就是執行器怎麼和 InnoDB 存儲引擎打交道了。
對於 Server 層來說,它是不知道存儲引擎的實現細節的,而是通過定義的 API 接口和存儲引擎通信。可以理解爲存儲引擎是一個類,然後每個實例(InnoDB)都通過一個特殊的處理程序接口與 MySQL 服務器通信。
InnoDB 引擎層:
現在已經到了引擎層了,存儲引擎主要負責數據的存儲和讀取
-
1. 調用存儲引擎接口後,會先從 Buffer Pool 獲取數據頁,如果沒有就從磁盤中讀入 Buffer Pool,然後判斷更新前後的記錄是否一樣
-
2. 開啓事務,修改數據之前先記錄 undo log,寫入 Buffer Pool 的 undo page
-
3. 開始更新 page data 中的記錄,被修改的數據頁稱爲髒頁,修改會被記錄到內存中的 redo log buffer 中,再刷盤到磁盤的 redo log 文件,此時事務是 perpare 階段
-
4. 這個時候更新就完成了,當時髒頁不會立即寫入磁盤,而是由後臺線程完成,這裏會用 double write 來保證髒頁刷盤的可靠性
-
5. 還沒結束呢,這時候可以通知 Server 層,可以正式提交數據了, 執行器記錄 binlog cache,事務提交時纔會將該事務中的 binglog 刷新到磁盤中
-
6. 這個時候 Update 語句完成了 Buffer Pool 中數據頁的修改、undo 日誌、redo log 緩存記錄,以及記錄 binlog cache 緩存
-
7. commit 階段,這個階段是將 redo log 中事務狀態標記爲 commit
-
8. 此時 binlog 和 redo log 都已經寫入磁盤,如果觸發了刷新髒頁的操作,先把髒頁 copy 到 double write buffer 裏,Double Write Buffer 的內存數據刷到磁盤中的共享表空間 ibdata,再刷到數據磁盤上數據文件 ibd
-
9. 流程完結
什麼是二階段提交?
二階段提交,顧名思義,會包含 2 個階段:
prepare 階段,協調器會詢問所有執行器,是否可以提交事務
commit 階段,協調器會通知執行器進行提交操作
update 的執行階段也用到了,比如:
-
• prepare 階段:將 redo log 對應的事務狀態設置爲 prepare,然後將 redo log 刷新到硬盤;
-
• commit 階段:將 binlog 刷新到磁盤,接着調用引擎的提交事務接口,將 redo log 狀態設置爲 commit(將事務設置爲 commit 狀態後,刷入到磁盤 redo log 文件)
總結
今天的分享就到這了,我們平時一條 Update 語句其實內部會經歷很多流程,語句解析、日誌 WAL,Buffer Pool 等。通過今天這篇文章的分享相信大家對流程已經很清晰了,後續將繼續帶來 Redo Log、UndoLog 等內容,敬請期待!
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/eep-JDNya25ys4DDzuKCww