mysql_一條更新語句的執行流程

一條更新語句的執行流程

create table T(ID int primary key, c int);
update T set c=c+1 where ID=2;
在一個表上有更新的時候,跟這個表有關的查詢緩存會失效,因此這條語句就會把表 T 上全部緩存結果都清空。這也就是咱們通常不建議使用查詢緩存的緣由。
與查詢流程不同的是,更新流程還涉及兩個重要的日誌模塊:redo log(重作日誌)和 binlog(歸檔日誌)。若是接觸 MySQL,那這兩個詞確定是繞不過的,我後面的內容裏也會不斷地和你強調。不過話說回來,redo log 和 binlog 在設計上有不少有意思的地方,這些設計思路也能夠用到你本身的程序裏。

redo log(重作日誌)

在 MySQL 裏,若是每一次的更新操做都須要寫進磁盤,而後磁盤也要找到對應的那條記錄,而後再更新,整個過程 IO 成本、查找成本都很高。
MySQL裏使用 WAL 技術,WAL 的全稱是 Write-Ahead Logging,它的關鍵點就是先寫日誌,再寫磁盤。
具體來講,當有一條記錄須要更新的時候,InnoDB 引擎就會先把記錄寫到 redo log裏面,並更新內存,這個時候更新就算完成了。同時,InnoDB 引擎會在適當的時候,將這個操做記錄更新到磁盤裏面,而這個更新每每是在系統比較空閒的時候作。
InnoDB 的 redo log 是固定大小的,好比能夠配置爲一組 4 個文件,每一個文件的大小是 1GB,那麼總共就能夠記錄 4GB 的操做。從頭開始寫,寫到末尾就又回到開頭循環寫。
有了 redo log,InnoDB 就能夠保證即便數據庫發生異常重啓,以前提交的記錄都不會丟失,這個能力稱爲crash-safe。

binlog(歸檔日誌)

redo log是innoDB 引擎特有的日誌。而binlog是mysql server層的日誌。 爲何要有兩份日誌:mysql

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

redo log和binlog的區別:sql

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

更新語句的執行流程

怎樣讓數據庫恢復到半個月內任意一秒的狀態?

redo log和binlog的總結

redo log是爲了保證innoDB引擎的crash-safe能力,也就是說在mysql異常宕機重啓的時候,以前提交的事務能夠保證不丟失;(由於成功提交的事務確定是寫入了redo log,能夠從redo log恢復)

binlog是歸檔日誌,將每一個更新操做都追加到日誌中。這樣當須要將日誌恢復到某個時間點的時候,就能夠根據全量備份+binlog重放實現。 若是沒有開啓binlog,那麼數據只能恢復到全量備份的時間點,而不能恢復到任意時間點。  若是連全量備份也沒作,mysql宕機,磁盤也壞了,那就很尷尬了。。

binlog並不具有crash-safe的能力。

問題

  1. 手動用begin開啓事務,而後執行update語句,再而後執行commit語句,那上面的update更新流程哪些是update語句執行以後作的,哪些是commit語句執行以後作的?
實際上,redo log在內存中有一個redo log buffer,binlog 也有一個binlog cache.因此在手動開啓的事務中,你執行sql語句,實際上是寫到redo log buffer和binlog cache中去的(確定不多是直接寫磁盤日誌,一個是性能差一個是回滾的時候不可能去回滾磁盤日誌吧),而後當你執行commit的時候,首先要將redo log的提交狀態遊prepare改成commit狀態,而後就要把binlog cache刷新到binlog日誌(可能也只是flush到操做系統的page cache,這個就看你的mysql配置),redo log buffer刷新到redo log 日誌(刷新時機也是能夠配置的)。 若是你回滾的話,就只用把binlog cache和redo log buffer中的數據清除就好了。
  1. 在update過程當中,mysql忽然宕機,會發生什麼狀況?
1.若是redolog寫入了,處於prepare狀態,binlog還沒寫入,那麼宕機重啓後,redolog中的這個事務就直接回滾了。
2. 若是redolog寫入了,binlog也寫入了,但redolog尚未更新爲commit狀態,那麼宕機重啓之後,mysql會去檢查對應事務在binlog中是否完整。若是是,就提交事務;若是不是,就回滾事務。 (redolog處於prepare狀態,binlog完整啓動時就提交事務,爲啥要這麼設計? 主要是由於binlog寫入了,那麼就會被從庫或者用這個binlog恢復出來的庫使用,爲了數據一致性就採用了這個策略)
redo log和binlog是經過xid這個字段關聯起來的。

參考

極客時間《mysql實戰45講》數據庫

相關文章
相關標籤/搜索