02 SQL更新語句執行流程 與查詢流程不一樣的是,更新流程還涉及兩個重要的日誌模塊。 redo log(重做日誌)和 binlog(歸檔日誌) redo log 物理日誌 binlog 邏輯日誌 redo log WAL 的全稱是 Write-Ahead Logging。 關鍵點就是先寫日 ...
02 SQL更新語句執行流程
與查詢流程不一樣的是,更新流程還涉及兩個重要的日誌模塊。
redo log(重做日誌)和 binlog(歸檔日誌)
redo log 物理日誌 binlog 邏輯日誌
redo log
WAL 的全稱是 Write-Ahead Logging。
關鍵點就是先寫日誌,再寫磁碟,用來提升更新效率。
具體來說,當有一條記錄需要更新的時候,InnoDB 引擎就會先把記錄寫到 redo log 裡面,並更新記憶體,這個時候更新就算完成了。同時,InnoDB 引擎會在適當的時候,將這個操作記錄更新到磁碟裡面,而這個更新往往是在系統比較空閑的時候做。
InnoDB 的 redo log 是固定大小的,比如可以配置為一組 4 個文件,每個文件的大小是 1GB,那麼這塊“粉板”總共就可以記錄 4GB 的操作。從頭開始寫,寫到末尾就又回到開頭迴圈寫,並覆蓋之前的記錄。
write pos是當前記錄的位置,check point 是當前要擦除的位置。
有了 redo log,InnoDB 就可以保證即使資料庫發生異常重啟,之前提交的記錄都不會丟失,這個能力稱為 crash-safe。
binlog
redo log 是 InnoDB 引擎特有的日誌,Server 層也有自己的日誌,稱為 binlog(歸檔日誌)。
redo log 和binlog的區別:
- redo log 是 InnoDB 引擎特有的;binlog 是 MySQL 的 Server 層實現的,所有引擎都可以使用。
- redo log 是物理日誌,記錄的是“在某個數據頁上做了什麼修改”;binlog 是邏輯日誌(邏輯操作(原始sql語句)),記錄的是這個語句的原始邏輯,比如“給 ID=2 這一行的 c 欄位加 1 ”。
- redo log 是迴圈寫的,空間固定會用完;binlog 是可以追加寫入的。“追加寫”是指 binlog 文件寫到一定大小後會切換到下一個,並不會覆蓋以前的日誌。
將 redo log 的寫入拆成了兩個步驟:prepare 和 commit,這就是"兩階段提交"。
圖中淺色框表示是在 InnoDB 內部執行的,深色框表示是在執行器中執行的。
兩階段提交使得兩份日誌之間的邏輯一致。
具體原因:
-
先寫 redo log 後寫 binlog。假設在 redo log 寫完,binlog 還沒有寫完的時候,MySQL 進程異常重啟。redo log 寫完之後,系統即使崩潰,仍然能夠把數據恢復回來,所以恢復後這一行 c 的值是 1。但是由於 binlog 沒寫完就 crash 了,這時候 binlog 裡面就沒有記錄這個語句。因此,之後備份日誌的時候,存起來的 binlog 裡面就沒有這條語句。
如果需要用這個 binlog 來恢復臨時庫的話,由於這個語句的 binlog 丟失,這個臨時庫就會少了這一次更新,恢復出來的這一行 c 的值就是 0,與原庫的值不同。
-
先寫 binlog 後寫 redo log。如果在 binlog 寫完之後 crash,由於 redo log 還沒寫,崩潰恢復以後這個事務無效,所以這一行 c 的值是 0。但是 binlog 裡面已經記錄了“把 c 從 0 改成 1”這個日誌。所以,在之後用 binlog 來恢復的時候就多了一個事務出來,恢復出來的這一行 c 的值就是 1,與原庫的值不同。
如果不使用“兩階段提交”,那麼 資料庫的狀態 就有可能和 用它的日誌恢復出來的庫 的狀態不一致。
問:在什麼場景下,一天一備會比一周一備更有優勢呢?或者說,它影響了這個資料庫系統的哪個指標?
答:一天一備的最長恢復時間更短,當然這個是有成本的,因為更頻繁全量備份需要消耗更多存儲空間,所以這個 RTO 是成本換來的,就需要你根據業務重要性來評估了。(用空間換取時間)。