日誌系統:一條SQL更新語句是如何執行的?&&閱讀筆記

閱讀完文章後,自己的一些小記錄。原文

前言

一條更新語句的執行流程與查詢流程類似 一條SQL查詢語句是如何執行的
在這裏插入圖片描述
與查詢流程不一樣的是,更新流程還涉及兩個重要的日誌模塊:redo log(重做日誌)和binlog(歸檔日誌)

redo log

記賬例子:
酒店掌櫃有一個粉板,專門用來記錄客人的賒賬記錄。如果賒賬的人不多,那麼他可以把顧客名和賬目寫在板上。但如果賒賬的人多了,粉板總會有記不下的時候,這個時候掌櫃一定還有一個專門記錄賒賬的賬本。

如果有人要賒賬或者還賬的話,掌櫃一般有兩種做法:

  • 一種做法是直接把賬本翻出來,把這次賒的賬加上去或者扣除掉;
  • 另一種做法是先在粉板上記下這次的賬,等打烊以後再把賬本翻出來覈算。

當聲音紅火時,選擇先把帳記在白板上,等閒的時候再寫到賬本。

粉板和賬本配合的整個過程,就是MySQL裏的WAL技術,Write-Ahead Logging,它的關鍵點就是先寫日誌,再寫磁盤,也就是先寫粉板,等不忙的時候再寫賬本。

當有新記錄需要更新時,InnoDB引擎會將記錄寫到redo log(粉板)裏,並更新內存,這時更新就算完成了。然後InnoDB引擎會在系統比較空閒的時候,將操作記錄更新到磁盤。

如果某天賒賬的特別多,粉板寫滿了,這個時候就由不得你空閒了,只好放下手中活,把粉板中的一部分賒賬記錄更新到賬本中,然後把這些記錄從粉板上擦掉,爲記新賬騰出空間。這個原因,也是我們sql語句偶爾出現很慢的原因,可能是在清理redo log日誌

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

在這裏插入圖片描述
redo log可以保證即使數據庫發生異常重啓,之前提交的記錄都不會丟失,這個能力稱爲crash-safe

重要的日誌模塊:binlog

redo log是InnoDB引擎特有的日誌,而Server層也有自己的日誌,稱爲binlog(歸檔日誌)

重點來了,爲什麼要有兩份日誌?
MySQL自帶的引擎是MyISAM,MyISAM並沒有crash-safe的能力
兩種日誌的差異:

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

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)狀態,更新完成

淺色框在InnoDB內部執行的,深色框在執行器中執行的
在這裏插入圖片描述
redo log的寫入拆成了兩個步驟:prepare和commit,這就是"兩階段提交"。

兩階段提交

兩階段提交的作用是讓兩份日誌的邏輯一致!
爲什麼日誌需要“兩階段提交”。這裏不妨用反證法來進行解釋。

  • 先寫redo log後寫binlog。假設在redo log寫完,binlog還沒有寫完的時候,MySQL進程異常重啓。redo log寫完之後,系統即使崩潰,仍然能夠把數據恢復回來。但是由於binlog裏面沒有記錄這個語句。因此,之後備份日誌的時候,存起來的binlog裏面就沒有這條語句。需要用這個binlog來恢復臨時庫的話,由於這個語句的binlog丟失,這個臨時庫就會少了這一次更新,與原庫的值不同。
    -先寫binlog後寫redo log。如果在binlog寫完之後crash,由於redo log還沒寫,崩潰恢復以後這個事務無效。但是binlog裏面已經記錄了。所以,在之後用binlog來恢復的時候就多了一個事務出來,恢復出來的值,與原庫的值不同。

可以看到,如果不使用“兩階段提交”,那麼數據庫的狀態就有可能和用它的日誌恢復出來的庫的狀態不一致。

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