mysql日志系統 SQL 邏輯日志 物理日志


日志系統 SQL更新語句的執行

更新語句執行的流程

        更新語句執行的流程和查詢語句執行的流程一樣

        

        注意:

        在一個表上有更新的操作的時候,和這個表相關的查詢緩存就會被清空

 

        在經歷分析器,優化器,和執行器存儲引擎的歷程中,還多了重要的日志模塊

        Redo log 重做日志

        Bin log 歸檔日志

        

        Redolog 物理日志

            是innodb 引擎獨有的日志模塊

 

它的關鍵點就是更新的時候先寫日志,再寫磁盤,在任務不忙的時候將大量的積累更新操作一塊兒進行IO寫入磁盤

 

InnoDBredo log是固定大小的,比如可以配置為一組4個文件,每個文件的大小是1GB,那么這塊"粉板"總共就可以記錄4GB的操作。從頭開始寫,寫到末尾就又回到開頭循環寫,如下面這個圖所示

write pos是當前記錄的位置,一邊寫一邊后移,寫到第3號文件末尾后就回到0號文件開頭。checkpoint是當前要擦除的位置,也是往后推移並且循環的,擦除記錄前要把記錄更新到數據文件。

 

write poscheckpoint之間的是"粉板"上還空着的部分,可以用來記錄新的操作。如果write pos追上checkpoint,表示"粉板"滿了,這時候不能再執行新的更新,得停下來先擦掉一些記錄,把checkpoint推進一下。

 

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

 

Binlog 邏輯日志

 

        是service層日志模塊

        所有引擎都可以用

        Binlog以追加的方式記錄邏輯操作 是由執行器生成的

 

        為什么會有兩份日志模塊?

因為最開始MySQL里並沒有InnoDB引擎。MySQL自帶的引擎是MyISAM,但是MyISAM沒有crash-safe的能力,binlog日志只能用於歸檔。而InnoDB是另一個公司以插件形式引入MySQL的,既然只依靠binlog是沒有crash-safe能力的,所以InnoDB使用另外一套日志系統——也就是redo log來實現crash-safe能力

 

兩種日志特點對比:

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

 

 

 

執行器和innodb在執行數據更新的內部流程

  1. 執行器先找引擎取ID=2這一行。ID是主鍵,引擎直接用樹搜索找到這一行。如果ID=2這一行所在的數據頁本來就在內存中,就直接返回給執行器;否則,需要先從磁盤讀入內存,然后再返回。

     

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

 

  1. 引擎將這行新數據更新到內存中,同時將這個更新操作記錄到redo log里面,此時redo log處於prepare狀態。然后告知執行器執行完成了,隨時可以提交事務。

 

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

 

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

 

執行流程圖,

圖中淺色框表示是在InnoDB內部執行的,

深色框表示是在執行器中執行的

為什么日志需要"兩階段提交?

        重點:

        Binlog 的完成在redolog 的prepare和commit之間

        在binlog之前 redolog已經准備好在內存中,但是未寫入磁盤

        在binlog之后 redolog 才處於提交狀態准備寫入磁盤。

        Redolog 和binlog是兩個獨立的階段,並不依賴

        

        即,數據已經在內存中修改完畢,修改數據的操作也記錄完了,

但是數據庫的磁盤文件還沒有真正寫入。

 

假設當前ID=2的行,字段c的值是0,再假設執行update語句過程中在寫完第一個日志后,第二個日志還沒有寫完期間發生了crash

  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用於保證crash-safe能力。innodb_flush_log_at_trx_commit這個參數設置成1的時候,表示每次事務的redo log都直接持久化到磁盤。這個參數建議你設置成1,這樣可以保證MySQL異常重啟之后數據不丟失。

 

sync_binlog這個參數設置成1的時候,表示每次事務的binlog都持久化到磁盤。這個參數建議你設置成1,這樣可以保證MySQL異常重啟之后binlog不丟失

 

 

 

 

        

        


免責聲明!

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



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