MySQL一條更新語句的執行流程


更新語句的整體流程

  1. 連接數據庫

  2. 清空當前表對應的所有緩存

  3. 分析器分析詞法和語法

  4. 優化器決定使用什么索引

  5. 執行器負責具體執行

重要的日志模塊:redo log

MySQL的WAL技術
  • 全稱是Write-Ahead Logging
  • InnoDB 引擎特有的日志
  • 先寫日志,再寫磁盤
  • 詳解如下:

1、當有一條記錄需要更新的時候,InnoDB引擎就會把記錄寫到redo log里面,並且更新內存

2、InnoDB引擎會在適當的時候,將這個操作記錄更新到磁盤里面

redo log存儲在哪里?

InnoDB引擎先把記錄寫到redo log 中,redo log 在哪,它也是在磁盤上,這也是一個寫磁盤的過程, 但是與更新過程不一樣的是,更新過程是在磁盤上隨機IO,費時。 而寫redo log 是在磁盤上順序IO。效率要高。

如果redo log滿了怎么辦?

InnoDB 的 redo log 是固定大小的,比如可以配置為一組 4 個文件,每個文件的大小是 1GB,那么總共就可以記錄 4GB 的操作。從頭開始寫,寫到末尾就又回到開頭循環寫。

重要的日志模塊:binlog

  • Mysql自帶的日志模塊
  • 單獨的binlog沒有crash-safe的能力,只能用於歸檔

redo log和binlog的不同

  • redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 層實現的,所有引擎都可以使用。
  • redo log 是物理日志,記錄的是“在某個數據頁上做了什么修改”;binlog 是邏輯日志,記錄的是這個語句的原始邏輯,比如“給 ID=2 這一行的 c 字段加 1 ”。
  • redo log 是循環寫的,空間固定會用完;binlog 是可以追加寫入的。“追加寫”是指 binlog 文件寫到一定大小后會切換到下一個,並不會覆蓋以前的日志。

InnoDB引擎部分在執行這個簡單的update語句的時候的內部流程

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

 

兩階段提交

為什么必須有“兩階段提交”呢?這是為了讓兩份日志之間的邏輯一致

答:用反證法。

1、先寫 redo log 后寫 binlog。假設在 redo log 寫完,binlog 還沒有寫完的時候,MySQL 進程異常重啟。 由於我們前面說過的,redo log 寫完之后,系統即使崩潰,仍然能夠把數據恢復回來,所以恢復后這一行 c 的值是 1。 但是由於 binlog 沒寫完就 crash 了,這時候 binlog 里面就沒有記錄這個語句。因此,之后備份日志的時候, 存起來的 binlog 里面就沒有這條語句。然后你會發現,如果需要用這個 binlog 來恢復臨時庫的話, 由於這個語句的 binlog 丟失,這個臨時庫就會少了這一次更新,恢復出來的這一行 c 的值就是 0,與原庫的值不同。

2、先寫 binlog 后寫 redo log。如果在 binlog 寫完之后 crash,由於 redo log 還沒寫,崩潰恢復以后這個事務無效, 所以這一行 c 的值是 0。但是 binlog 里面已經記錄了“把 c 從 0 改成 1”這個日志。所以, 在之后用 binlog 來恢復的時候就多了一個事務出來,恢復出來的這一行 c 的值就是 1,與原庫的值不同。

redo log 和 binlog 都可以用於表示事務的提交狀態,而兩階段提交就是讓這兩個狀態保持邏輯上的一致。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM