02.日誌系統:一條SQL更新語句是如何執行的?

   咱們仍是從一個表的一條更新語句提及,咱們建立下面一張表:數據庫

create table T(ID int primary key, c int);

   若是要將ID=2這一行c的值加1,SQL能夠這麼寫:優化

update T set c=c+1 where ID=2;

   前一篇文章介紹過SQL語句基本的執行鏈路,能夠確認的說,查詢語句的那一套流程,更新語句也是一樣會走一遍。在執行語句前要先鏈接數據庫,這是鏈接器的工做。接下來,分析器會經過詞法和語法解析知道這是一條更新語句,優化器決定要使用ID這個索引。而後執行器負責具體執行,找到這一行,而後更新。日誌

  與查詢流程不同的是,更新流程還涉及兩個重要的日誌模塊:redo log(重作日誌)和binlog(歸檔日誌)。code

  • redo log

  MySQL裏面常常說到的WAL技術的全稱是Write-Ahead Logging,它的關鍵點就是行寫日誌再寫磁盤。具體來講,當有一條記錄須要更新的時候,InnoDB引擎會先把記錄寫到redo log裏面,並更新內存,這個時候更新就算完成了。同時InnoDB引擎會在適當的時候,將這個操做記錄更新到磁盤裏面,而這個更新每每是在系統比較閒的時候作。blog

  InnoDB的redo log是固定在小的,好比能夠配置爲一組4個文件,每一個文件的大小是1GB,那麼總共就能夠記錄4GB的操做,如圖所示:索引

   從頭開始寫,寫到末尾又回到開頭循環寫,write pos是當前記錄的位置,一邊寫一邊後移,寫到3號文件末尾後就回到0號文件開頭。checkpoint是當前要擦除的位置,擦出記錄前要把記錄更新到數據文件中。若是write pos追上checkpoint,這個時候不能再執行新的更新,得停下來先擦除一些記錄,把checkpoint推動一下。接口

   有了redo log,InnoDB就能夠保證即便在數據庫發生異常重啓,以前提交的記錄都不會丟失,這個能力稱爲crash-safe。  進程

  • binlog

  MySQL總體來看,其實就兩塊:一塊是Server層,它主要作的是MySQL功能層面的事情;還有一塊就是引擎層,負面存儲相關的具體事宜,上面說到的redo log是InnoDB引擎特有的日誌,而Server層也有本身的日誌,稱爲binlog。事務

 爲何會有兩份日誌呢?由於最開始MySQL並無InnoDb引擎,MySQL自帶的引擎是MyISAM,但MyISAM並無crash-safe能力,binlog日誌只能用於歸檔。內存

redo log日誌和binlog日誌有如下3個不一樣點:

  1. redo log 是InnoDB引擎特有的;binlog 是MySQL的Server層實現的,全部引擎均可以使用。
  2. redo log 是物理日誌,記錄的是「在某個數據頁上作了什麼修改」;binlog是邏輯日誌,記錄的是這個語句的原始邏輯,好比"給ID=2這一行的c字段+1"。
  3. redo log 是循環寫的,空間固定會用完;binlog是能夠追加寫入的,「追加寫」是指binlog文件寫到必定的大小後會切換到下一個,並不會覆蓋之前的日誌。

那麼執行一個簡單的update語句的內部流程以下:

  1. 執行器先找引擎取ID=2這一行,ID是主鍵,引擎直接用樹搜索找到這一行,若是ID=2這一行所在的數據頁原本就在內存中,就直接返回給執行器;不然,須要先從磁盤讀入內存,而後返回。
  2. 執行器拿到引擎返回的行數據,把這個值+1,行到新的一行數據,再調用引擎接口寫入這行新數據。
  3. 引擎將這行數據更新到內存中,同時將這個更新操做記錄到redo log裏面,此時redo log處理prepare狀態,而後告知執行器執行完了,隨時能夠提交事務。
  4. 執行器生成這條操做的binlog,並把binlog寫入磁盤。
  5. 執行器調用引擎的提交事務接口,引擎把剛剛寫入redo log改爲提交(commit)狀態,更新完成。

將redo log的寫入折成了兩個步驟:prepare和commit,這就是「兩階段提交」。

  • 兩階段提交
  1. 先寫redo log 後寫binlog。假設在redo log寫完後,binlog尚未寫完的時候,MySQL進程異常重啓,根據redo log恢復回來後這一行數據c=1,但因爲binlog沒有寫完就crash了,這個時候binglog裏面就沒有這條更新語句,若是須要用這個binlog來恢復臨時庫的話,這個臨時庫就會少一次更新,恢復出來的數據c=0。
  2. 先寫binlog後寫redo log。若是binlog寫完以後crash,因爲redo log尚未寫完,崩潰恢復後這個事務無效,因此這一行的c=0,但時,binlog裏面已經記錄了c=1,因此以後用binlog恢復出來的數據c=1寫原庫的值不一樣。

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

相關文章
相關標籤/搜索