SQL實戰研究InnoDB架構設計

update `user` set `name`='xxx' where `id`=1;

業務系統通過一個數據庫連接發給MySQL,經過SQL接口、解析器、優化器、執行器,解析SQL語句,生成執行計劃,接着由執行器負責執行該計劃,調用InnoDB的接口去實際執行。

本文研究存儲引擎的架構設計,探索存儲引擎內部如何完成一條更新語句。

InnoDB的內存結構:緩衝池

InnoDB內部放在內存裏的組件,緩衝池(Buffer Pool),會緩存很多數據, 以便之後查詢時,若緩衝池有數據,無需查磁盤:

所以當InnoDB執行更新語句時 ,如對“id=1”這行數據,會先將“id=1”這行數據看是否在緩衝池:

  • 若不在,則直接從磁盤裏加載到緩衝池,接着對這行記錄加獨佔鎖(更新“id=1”這行數據時,肯定不允許別人同時更新)

undo日誌文件:讓你更新的數據可回滾

假設“id=1”這行數據的name原來是“Java”,現在我們要更新爲“Edge”,則此時得先把要更新的原來的值“Java”和“id=1”這些信息,寫入undo日誌文件。

若執行一個更新語句,要是他在一個事務裏,則事務提交前,我們都可以對數據進行回滾,即把你更新爲“Edge”的值回滾到之前的“Java”。

所以考慮到後續可能需要回滾數據,這裏會把你更新前的值寫入undo日誌文件:

更新buffer pool

當要更新的那行記錄從磁盤文件加載到緩衝池,同時對其鎖後,而且還把更新前的舊值寫入undo日誌文件後,就能開始更新該行記錄。

更新時,先更新緩衝池中的記錄,此時這個數據就是髒數據了。

把內存裏的“id=1”這行數據的name字段修改爲“Edge”,爲何此時這行數據就是髒數據了?因爲這時磁盤上 中“id=1”這行數據的name還是“Java”,但內存裏這行數據已被修改,所以它就是髒數據:

Redo Log Buffer

萬一系統宕機,如何避免數據丟失?

現在已修改了內存數據,但還沒修改磁盤數據,若此時MySQL所在機器宕機,內存裏修改過的數據就會丟失,咋辦?

這時,就得將對內存所做的修改寫到Redo Log Buffer,也是內存裏的一個緩衝區,存放redo日誌。

redo日誌,記錄你對數據做了什麼修改,如對id=1這行記錄修改了name字段的值爲Edge。

redo日誌就是在MySQL宕機時,用來恢復你更新過的數據。

若還沒提交事務,MySQL宕機了,咋辦?

在數據庫中,哪怕執行一條SQL語句,其實也可算做一個獨立事務,只有當你提交事務後,SQL語句纔算執行結束。

所以至此,其實還沒提交事務,若此時MySQL宕機,導致內存裏Buffer Pool中的修改過的數據丟失了,同時你寫入Redo Log Buffer中的redo日誌也會丟失,這咋辦?

其實沒必要驚恐,因爲這條更新語句,沒提交事務,就代表他還沒執行成功,此時MySQL宕機了,雖然導致內存的數據更新都丟失了,但磁盤上的數據依然還停留在原樣。

即“id=1”那行數據的name還是原值,所以此時你的這個事務就是執行失敗了,沒能成功完成更新,那你就會收到一個數據庫異常。然後當MySQL重啓正常後,你會發現你的數據並沒有任何變化。所以此時即使MySQL宕機,也不會有任何問題。

提交事務時,將redo日誌寫盤

現在真的想提交一個事務,就會根據策略將redo log從redo log buffer裏刷盤。

該策略可通過innodb_flush_log_at_trx_commit配置:

  • 參數=0時,那你提交事務時,不會把redo log buffer裏的數據刷盤,此時可能你都提交事務了,結果MySQL宕機了,然後此時內存裏的數據全部丟失。相當於你提交事務成功了,但由於MySQL突然宕機,導致內存中的數據和redo日誌都丟了。

  • 參數=1,你提交事務時,就必須把redo log從內存刷盤,只要事務提交成功,則redo log必然在磁盤

那麼只要提交事務成功後,redo日誌一定在磁盤,此時你肯定會有一條redo日誌說,“我此時對哪個數據做了一個什麼修改,如name修改爲Edge了”。

即使此時Buffer Pool中更新過的數據還沒刷盤,此時內存數據是更新後的“name=Edge”,而磁盤上的數據還是未更新的“name=Java”。

提交事務後,可能處於的一個狀態:

此時,若提交事務後處於上圖狀態,然後MySQL突然宕機,也不會丟失數據。

雖然內存裏的修改成name=Edge的數據會丟,但redo日誌裏已經記錄:對某數據做了修改name=Edge。

所以之前由於系統崩潰,而現在MySQL重啓後,還能根據redo日誌,恢復之前做過的修改:

若innodb_flush_log_at_trx_commit=2呢?

提交事務時,把redo日誌寫入磁盤文件對應的os cache緩存,而不是直接進入磁盤文件,可能1s後,才把os cache裏的數據寫入到磁盤文件。這種模式下,提交事務後,redo log可能僅停留在os cache內存緩存,還沒實際進入磁盤文件,若此時宕機,則os cache裏的redo log就會丟失,同樣會讓你感覺提交事務了,但結果數據丟了:

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