《Mysql 一條 SQL 更新語句是如何執行的?(Redo log)》


一:更新流程

  - 對於更新來說,也同樣會根據 SQL 的執行流程進行。

    - 

  - 連接器

    - 連接數據庫,具體的不做贅述。

  - 查詢緩存

    - 在一個表上有更新的時候,跟這個表有關的查詢緩存會失效。

    - 這也就是我們一般不建議使用查詢緩存的原因。

  - 分析器

    - 接下來,分析器會通過詞法和語法解析知道這是一條更新語句。

  - 優化器

    - 優化器決定要使用 ID 這個索引。

  - 執行器

    - 然后,執行器負責具體執行,找到這一行,然后更新。

  - PS

    - 與查詢流程不一樣的是,更新流程還涉及兩個重要的日志模塊,它們正是我們今天要討論的主角:

    - redo log(重做日志)和 binlog(歸檔日志)

 

二: redo log

  - Mysql 更新存在的問題

    - 在 MySQL 中,如果每一條更新記錄,都需要寫入磁盤

    - 然后磁盤也要找到對應的那條記錄,然后再更新,整個過程 IO 成本、查找成本都很高

    - 為了解決這個問題,MySQL 的設計者就用了 redo log 的概念來解決這個問題。

 

  - redo log 概述

    - redo log 是 InnoDB 獨有的,屬於 存儲引擎層

 

  - redo log 工作流程

    - 具體來說,當有一條記錄更新的時候,InnoDB 引擎就會先把記錄寫到 redo log 里面,並更新內存,這個時候更新就算完成了

    - 同時,InnoDB 會在適當的時候,將這個操作記錄更新到磁盤里面.

    - PS

      - InnoDB 的 redo log 是固定大小的

        - 比如可以配置為一組 4 個文件,每個文件的大小是 1GB,那么總共就可以記錄 4GB 的操作。

        - 從頭開始寫,寫到末尾就又回到開頭循環寫

      - 當 redo log 被寫滿時候,這時候不能在執行新的更新,必須停下來,擦除一些 redo log 的日志,寫入磁盤

      - 有了 redo logInnoDB 就可以保證即使數據庫發生異常重啟,之前提交的記錄都不會丟失,這個能力稱為 crash-safe

 

三 :binlog

  - binlog 概述

    - binlog(歸檔日志) 是 Server 層特有的

 

  - 為什么會有兩份日志?

    - 因為最開始 MySQL 里並沒有 InnoDB 引擎。

    - MySQL 自帶的引擎是 MyISAM,但是 MyISAM 沒有 crash-safe 的能力,binlog 日志只能用於歸檔。

    - 而 InnoDB 是另一個公司以插件形式引入 MySQL 的,既然只依靠 binlog 是沒有 crash-safe 能力的

    - 所以 InnoDB 使用另外一套日志系統-- 就是 redo log 來實現 crash-safe 能力。

 

四 :binlog 和 redo log 的不同

  - redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 層實現的,所有引擎都可以使用。

  - redo log 是物理日志,記錄的是“在某個數據頁上做了什么修改

  - binlog 是邏輯日志,記錄的是這個語句的原始邏輯,比如“給 ID=2 這一行的 c 字段加 1 ”。

  - redo log 是循環寫的,空間固定會用完;

  - binlog 是可以追加寫入的。“追加寫”是指 binlog 文件寫到一定大小后會切換到下一個,並不會覆蓋以前的日志。

 

五:再看 Update 執行過程

  - 例如

    - mysql> update T set c=c+1 where ID=2;

 

  - 流程

    執行器先找引擎取 ID=2 這一行

      - ID 是主鍵,引擎直接用樹搜索找到這一行。

      - 如果 ID=2 這一行所在的數據頁本來就在內存中,就直接返回給執行器

      - 否則,需要先從磁盤讀入內存,然后再返回。

 

    - 執行器拿到引擎給的行數據

      - 把這個值加上 1,比如原來是 N,現在就是 N+1,得到新的一行數據,再調用引擎接口寫入這行新數據。

 

    - 引擎將這行新數據更新到內存中

      - 同時將這個更新操作記錄到 redo log 里面,此時 redo log 處於 prepare 狀態。

      - 然后告知執行器執行完成了,隨時可以提交事務。

 

    - 執行器生成這個操作的 binlog,並把 binlog 寫入磁盤。

 

    - 執行器調用引擎的提交事務接口,引擎把剛剛寫入的 redo log 改成提交(commit)狀態,更新完成。 

    - 

 

六:redo 的 “兩階段提交”

  - 根據上面的流程圖,可以看到,redo log 的寫入拆成了兩個步驟:prepare 和 commit,這就是"兩階段提交"。

 

  - 原因

    - 由於 redo log 和 binlog 是兩個獨立的邏輯

      - 如果不用兩階段提交,要么就是先寫完 redo log 再寫 binlog,或者采用反過來的順序,會導致數據的不一致出現。

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

  

  - 舉例一個完整的交易流程

    - 賬本記上 賣一瓶可樂(redo log為 prepare狀態),然后收錢放入錢箱(bin log記錄)然后回過頭在賬本上打個勾(redo log置為commit)表示一筆交易結束。

    - 如果收錢時交易被打斷,回過頭來整理此次交易,發現只有記賬沒有收錢,則交易失敗,刪掉賬本上的記錄(回滾)

    - 如果收了錢后被終止,然后回過頭發現賬本有記錄(prepare)而且錢箱有本次收入(bin log),則繼續完善賬本(commit),本次交易有效。

 

七:小結

  - redo log 用於保證 crash-safe 能力。

    - innodb_flush_log_at_trx_commit 這個參數設置成 1 的時候,表示每次事務的 redo log 都直接持久化到磁盤。

    - 這個參數建議設置成 1,這樣可以保證 MySQL 異常重啟之后數據不丟失。

 

  - sync_binlog 這個參數設置成 1 的時候,表示每次事務的 binlog 都持久化到磁盤。

    - 這個參數也建議設置成 1,這樣可以保證 MySQL 異常重啟之后 binlog 不丟失。

 

  - 還介紹了與 MySQL 日志系統密切相關的“兩階段提交”。

    - 兩階段提交是跨系統維持數據邏輯一致性時常用的一個方案,即使你不做數據庫內核開發,日常開發中也有可能會用到。 


免責聲明!

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



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