MySQL回滾日志(undo?log)的作用和使用詳解
一、undo log的概念
undo log是mysql中比較重要的事務(wù)日志之一,顧名思義,undo log是一種用于撤銷(xiāo)回退的日志,在事務(wù)沒(méi)提交之前,MySQL會(huì)先記錄更新前的數(shù)據(jù)到 undo log日志文件里面,當(dāng)事務(wù)回滾時(shí)或者數(shù)據(jù)庫(kù)崩潰時(shí),可以利用 undo log來(lái)進(jìn)行回退。
二、undo log的作用
在MySQL中,undo log日志的作用主要有兩個(gè):
1、提供回滾操作【undo log實(shí)現(xiàn)事務(wù)的原子性】
我們?cè)谶M(jìn)行數(shù)據(jù)更新操作的時(shí)候,不僅會(huì)記錄redo log,還會(huì)記錄undo log,如果因?yàn)槟承┰驅(qū)е率聞?wù)回滾,那么這個(gè)時(shí)候MySQL就要執(zhí)行回滾(rollback)操作,利用undo log將數(shù)據(jù)恢復(fù)到事務(wù)開(kāi)始之前的狀態(tài)。
如我們執(zhí)行下面一條刪除語(yǔ)句:
delete from user where id = 1;
那么此時(shí)undo log會(huì)記錄一條對(duì)應(yīng)的insert 語(yǔ)句【反向操作的語(yǔ)句】,以保證在事務(wù)回滾時(shí),將數(shù)據(jù)還原回去。
再比如我們執(zhí)行一條update語(yǔ)句:
update user set name = "李四" where id = 1; ---修改之前name=張三
此時(shí)undo log會(huì)記錄一條相反的update語(yǔ)句,如下:
update user set name = "張三" where id = 1;
如果這個(gè)修改出現(xiàn)異常,可以使用undo log日志來(lái)實(shí)現(xiàn)回滾操作,以保證事務(wù)的一致性。
2、提供多版本控制(MVCC)【undo log實(shí)現(xiàn)多版本并發(fā)控制(MVCC)】
MVCC,即多版本控制。在MySQL數(shù)據(jù)庫(kù)InnoDB存儲(chǔ)引擎中,用undo Log來(lái)實(shí)現(xiàn)多版本并發(fā)控制(MVCC)。當(dāng)讀取的某一行被其他事務(wù)鎖定時(shí),它可以從undo log中分析出該行記錄以前的數(shù)據(jù)版本是怎樣的,從而讓用戶(hù)能夠讀取到當(dāng)前事務(wù)操作之前的數(shù)據(jù)【快照讀】。
下面解釋一下什么是快照讀,與之對(duì)應(yīng)的還有一個(gè)是---當(dāng)前讀。
快照讀:
SQL讀取的數(shù)據(jù)是快照版本【可見(jiàn)版本】,也就是歷史版本,不用加鎖,普通的SELECT就是快照讀。
當(dāng)前讀:
SQL讀取的數(shù)據(jù)是最新版本。通過(guò)鎖機(jī)制來(lái)保證讀取的數(shù)據(jù)無(wú)法通過(guò)其他事務(wù)進(jìn)行修改UPDATE、DELETE、INSERT、SELECT … LOCK IN SHARE MODE、SELECT … FOR UPDATE都是當(dāng)前讀。
三、undo log的存儲(chǔ)機(jī)制
undo log的存儲(chǔ)由InnoDB存儲(chǔ)引擎實(shí)現(xiàn),數(shù)據(jù)保存在InnoDB的數(shù)據(jù)文件中。在InnoDB存儲(chǔ)引擎中,undo log是采用分段(segment)的方式進(jìn)行存儲(chǔ)的。rollback segment稱(chēng)為回滾段,每個(gè)回滾段中有1024個(gè)undo log segment。在MySQL5.5之前,只支持1個(gè)rollback segment,也就是只能記錄1024個(gè)undo操作。在MySQL5.5之后,可以支持128個(gè)rollback segment,分別從resg slot0 - resg slot127,每一個(gè)resg slot,也就是每一個(gè)回滾段,內(nèi)部由1024個(gè)undo segment 組成,即總共可以記錄128 * 1024個(gè)undo操作。
下面以一張圖來(lái)說(shuō)明undo log日志里面到底存了哪些信息?
如上圖,可以看到,undo log日志里面不僅存放著數(shù)據(jù)更新前的記錄,還記錄著RowID、事務(wù)ID、回滾指針。其中事務(wù)ID每次遞增,回滾指針第一次如果是insert語(yǔ)句的話(huà),回滾指針為NULL,第二次update之后的undo log的回滾指針就會(huì)指向剛剛那一條undo log日志,依次類(lèi)推,就會(huì)形成一條undo log的回滾鏈,方便找到該條記錄的歷史版本。
四、undo log的工作原理
在更新數(shù)據(jù)之前,MySQL會(huì)提前生成undo log日志,當(dāng)事務(wù)提交的時(shí)候,并不會(huì)立即刪除undo log,因?yàn)楹竺婵赡苄枰M(jìn)行回滾操作,要執(zhí)行回滾(rollback)操作時(shí),從緩存中讀取數(shù)據(jù)。undo log日志的刪除是通過(guò)通過(guò)后臺(tái)purge線程進(jìn)行回收處理的。
同樣,通過(guò)一張圖來(lái)理解undo log的工作原理。
如上圖:
1、事務(wù)A執(zhí)行update操作,此時(shí)事務(wù)還沒(méi)提交,會(huì)將數(shù)據(jù)進(jìn)行備份到對(duì)應(yīng)的undo buffer,然后由undo buffer持久化到磁盤(pán)中的undo log文件中,此時(shí)undo log保存了未提交之前的操作日志,接著將操作的數(shù)據(jù),也就是Teacher表的數(shù)據(jù)持久保存到InnoDB的數(shù)據(jù)文件IBD。
2、此時(shí)事務(wù)B進(jìn)行查詢(xún)操作,直接從undo buffer緩存中進(jìn)行讀取,這時(shí)事務(wù)A還沒(méi)提交事務(wù),如果要回滾(rollback)事務(wù),是不讀磁盤(pán)的,先直接從undo buffer緩存讀取。
用undo log實(shí)現(xiàn)原子性和持久化的事務(wù)的簡(jiǎn)化過(guò)程:
假設(shè)有A、B兩個(gè)數(shù)據(jù),值分別為1,2。
- A. 事務(wù)開(kāi)始
- B. 記錄A=1到undo log中
- C. 修改A=3
- D. 記錄B=2到undo log中
- E. 修改B=4
- F. 將undo log寫(xiě)到磁盤(pán) -------undo log持久化
- G. 將數(shù)據(jù)寫(xiě)到磁盤(pán) -------數(shù)據(jù)持久化
- H. 事務(wù)提交 -------提交事務(wù)
之所以能同時(shí)保證原子性和持久化,是因?yàn)橐韵绿攸c(diǎn):
- 更新數(shù)據(jù)前記錄undo log。
- 為了保證持久性,必須將數(shù)據(jù)在事務(wù)提交前寫(xiě)到磁盤(pán),只要事務(wù)成功提交,數(shù)據(jù)必然已經(jīng)持久化到磁盤(pán)。
- undo log必須先于數(shù)據(jù)持久化到磁盤(pán)。如果在G,H之間發(fā)生系統(tǒng)崩潰,undo log是完整的,可以用來(lái)回滾。
- 如果在A - F之間發(fā)生系統(tǒng)崩潰,因?yàn)閿?shù)據(jù)沒(méi)有持久化到磁盤(pán),所以磁盤(pán)上的數(shù)據(jù)還是保持在事務(wù)開(kāi)始前的狀態(tài)。
缺陷:每個(gè)事務(wù)提交前將數(shù)據(jù)和undo log寫(xiě)入磁盤(pán),這樣會(huì)導(dǎo)致大量的磁盤(pán)IO,因此性能較差。 如果能夠?qū)?shù)據(jù)緩存一段時(shí)間,就能減少I(mǎi)O提高性能,但是這樣就會(huì)失去事務(wù)的持久性。
undo日志屬于邏輯日志,redo是物理日志,所謂邏輯日志是undo log是記錄一個(gè)操作過(guò)程,不會(huì)物理刪除undo log,sql執(zhí)行delete或者update操作都會(huì)記錄一條undo日志。
五、undo log的相關(guān)參數(shù)
- innodb_undo_directory
指定undo log日志的存儲(chǔ)目錄,默認(rèn)值為./。
- innodb_undo_logs
在MySQL5.6版本之后,可以通過(guò)此參數(shù)自定義多少個(gè)rollback segment,默認(rèn)值為128。
- innodb_undo_tablespaces
指定undo log平均分配到多少個(gè)表空間文件中,默認(rèn)值為0,即全部寫(xiě)入一個(gè)文件中。不建議修改為非0值,我們直接使用默認(rèn)值即可。
在InnoDB存儲(chǔ)引擎中,在啟動(dòng)日志中也會(huì)提示:不建議修改 innodb_undo_tablespaces為非0的值。
附錄:參考資料
http://www.dbjr.com.cn/article/244628.htm
http://www.dbjr.com.cn/article/244643.htm
《MySQL技術(shù)內(nèi)幕(第5版)》
到此這篇關(guān)于MySQL回滾日志(undo log)的文章就介紹到這了,更多相關(guān)MySQL回滾日志undo log內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MySQL報(bào)錯(cuò):sql_mode=only_full_group_by的4種輕松解決方法(含舉例)
今天學(xué)mysql函數(shù)的時(shí)候在自己服務(wù)器上的MySQL碰見(jiàn)了個(gè)奇怪的問(wèn)題,下面這篇文章主要給大家介紹了關(guān)于MySQL報(bào)錯(cuò):sql_mode=only_full_group_by的4種輕松解決方法,需要的朋友可以參考下2023-01-01MySQL 索引和數(shù)據(jù)表該如何維護(hù)
使用合適的數(shù)據(jù)類(lèi)型完成數(shù)據(jù)表創(chuàng)建和建立索引后,工作并沒(méi)有完結(jié)——你需要去維護(hù)數(shù)據(jù)表和索引以保證它們運(yùn)行良好。數(shù)據(jù)表維護(hù)的主要目的是查找和修復(fù)沖突,維護(hù)精確的索引統(tǒng)計(jì)和減少碎片。2021-05-05Mysql在線回收undo表空間實(shí)戰(zhàn)記錄
這篇文章主要給大家介紹了關(guān)于Mysql在線回收undo表空間的相關(guān)資料,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Mysql具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-09-09MySQL學(xué)習(xí)(七):Innodb存儲(chǔ)引擎索引的實(shí)現(xiàn)原理詳解
這篇文章主要介紹了Innodb存儲(chǔ)引擎索引的實(shí)現(xiàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2019-04-04MySQL學(xué)習(xí)第三天 Windows 64位操作系統(tǒng)下驗(yàn)證MySQL
MySQL學(xué)習(xí)第三天教大家如何在Windows 64位操作系統(tǒng)下驗(yàn)證MySQL,感興趣的小伙伴們可以參考一下2016-05-05mysql sql語(yǔ)句性能調(diào)優(yōu)簡(jiǎn)單實(shí)例
這篇文章主要介紹了 mysql sql語(yǔ)句性能調(diào)優(yōu)簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下2017-06-06