在整理undo log筆記前我感受它應該是在 undo、redo、bin log三者中須要整理的內容最少的。可是實際上並非想象的那麼簡單。html
關於undo log須要整理的兩大塊知識點分別是:mysql
一、簡介undo log、truncate、以及undo log如何幫你回滾事物(本篇分享) sql
二、undolog鏈條、ReadView、以及undo log如何幫你實現MVCC多版本併發控制(明天分享)
數據庫
若是你看了白日夢前面的分享的筆記,你確定知道了什麼表空間。其實所謂的表空間實際上是真實存在於磁盤上的數據文件。而這裏的所說的undolog表空間其實就是磁盤上專門存放undo log的文件。bash
表空間由不少 segment(段) 組成,而這衆多的段中有一種就是 undo segment。併發
默認狀況下undo segment 會存放於系統表空間中,或者說undo log默認會記錄在共享表空間文件中(文件真實存在)。測試
可是MySQL也提供了參數,讓你能夠控制MySQL講undo log寫入到單獨的表空間文件中去。尤爲是當你使用SSD這種存儲時,尤其推薦將undo log從共享表空間中拿出去。spa
默認狀況下undo log tablespace個數是0,也就是說若是你不干涉MySQL的配置。那麼MySQL就會幫你將undo log記錄到共享表空間中。線程
MySQL默認的配置文件 my.cnf 長下面這樣:設計
若是你如今僅僅是安裝了MySQL,而未曾啓動過mysql,那你去datadir中查看會發現它只是個空目錄。
可是當你啓動過MySQL以後,再去這個datadir中查看會發現裏面多了不少文件,其中就包括共享表空間文件ibdata1(可是沒有undolog表空間文件)。以下:
若是你想將undo log拿到undo log表空間文件中。那你能夠像下面這樣修改MySQL的配置文件my.cnf
修改完後經過以下命令啓動mysql
systemctl start mysqld.service
可是你會發現啓動不了,若是你去排查緣由就會發現:由於曾經初始化過 datadir 目錄中的文件,你添加的新配置innodb_undo_tablespaces和原來的配置是衝突的,須要開闢新的表空間文件,因此致使啓動失敗。
解決的方式:簡單粗暴的將換個datadir文件就好啦,因此若是你從一開始就想將undolog拿到單獨的表空間中,那麼最好從一開始就將這個配置添加進去,不然仍是挺麻煩的。
本文是第14篇,全文近100篇,點擊查看目錄
提到了undo log,就不得不說roll back segment這個知識點了。它並不難理解,你能夠閱讀下面的介紹瞭解一下。
InnoDB存儲引擎會先初始化好rollback segment(回滾段),在每一個回滾段中會記錄N個undo log segment,而咱們說的undo log就是在 undo log segment中申請出來的!
在早期的InnoDB版本中只有一個rollback segment,所以在同一時刻它支持的在線事物的上限被限制在1024個。
在MySQL5.7中回滾段已經支持到了128個(上限是128)。其中32個分配給臨時表空間。剩下的96個回滾段能夠分配給修改常規表中數據的事務。
用戶能夠經過參數innodb_rollback_segments
調整回滾段的數量。
另外,咱們上面提到的: 每一個回滾段中都記錄了N個undolog segment, 這裏的N和數據頁大小有關
InnoDB頁面大小 | 回滾段中的撤消插槽數(InnoDB頁面大小/ 16) |
---|---|
4096 (4KB) | 256 |
8192 (8KB) | 512 |
16384 (16KB) | 1024 |
32768 (32KB) | 204 |
65536 (64KB) | 4096 |
truncate意爲:截斷
其實結合 truncate table sql,就能更好的理解這個概念。當你不須要某個表中的數據時,你能夠執行truncate sql將表中的數據清空掉。一樣的undo log的truncate機制本質上就是爲undo log 表空間文件瘦身,將不須要的undo log清理掉。
在MySQL 5.6(包括5.6)以前Undo tablespace裏面的undo數據文件是沒法收縮的。也就是說在實例的運行過程當中若是遇到有大的事務,會把undo log的文件撐的很是大。浪費大量的空間甚至會把磁盤打爆。同時也增長了數據庫物理備份的時間。
在MySQL5.7中容許用戶在線truncate undo log
前提:必須使用獨立的undo表空間
而後配合以下的參數輔助:
建立數據表:
create table test ( id int primary key auto_increment, name varchar(64) );
而後不斷的往這個測試表中插入數據
insert into test(name) values(repeat('a',64)); insert into test(name) select name from test;
一邊插入一邊觀察undo 表空間文件的變化:你會發現undo003這個表空間文件已經超過了參數:innodb_max_undo_log_size=100M
指定的範圍,意味着這個undolog已經被標記爲可回收了。
當事物提交時,undo log並不會被當即刪除,由於可能存在其它的事物須要使用undo log將數據回滾到以前的版本。最終是否能夠刪除undo log由purge線程決定。
爲了讓pruge線程運行,能夠執行以下的sql
delete from test limit 1;
undo log有兩種類型,分別是 insert undo log 和 update undo log。
前者記錄的是insert 語句對應的undo log。
後者對應的是 update、delete 語句對應的undo log。
對於 insert 類型的sql,會在undo log中記錄下方纔你insert 進來的數據的ID,根據ID完成精準的刪除。
insert 類型的undo log長下面這樣:
可能你打眼一看上圖就能知道各部分都有啥用。
可是,不知道你會不會納悶這樣一個問題:不是說對於insert 類型的undo log MySQL記錄的是方纔插入行ID嗎?怎麼上圖整出來的了這麼多Col一、Col二、Col2。
實際上是MySQL設計的很周到,由於它是針對聯合主鍵設計的。
一條update sql對應undolog長以下這樣。
其實我感受不必記住這個圖,記住了也會忘。大概看一下它長什麼樣子就好。
重點是下面會分享的,undo log鏈條,而且你得知道這個鏈條能夠幫你實現事務的回滾
舉個例子:
對於 insert 類型的sql,會在undo log中記錄下方纔你insert 進來的數據的ID,當你想roll back時,根據ID完成精準的刪除。
對於delete類型的sql,會在undo log中記錄方纔你刪除的數據,當你回滾時會將刪除前的數據insert 進去。
對於update類型的sql,會在undo log中記錄下修改前的數據,回滾時只須要反向update便可。
對於select類型的sql,別費心了,select不須要回滾。
先看一個簡單的insert undo log 鏈條
有一個注意點:由於單純的insert sql不涉及多MVCC的能力。
因此一旦事務commit,這條insert undo log就能夠直接刪除了。
再看一個update類型的undo log
爲了方便畫圖,重點突出鏈條的概念我省略了update undo log的部份內容
一個事物A開啓後插圖了一條記錄:name = tom,MySQL會記錄下這樣一條undo log
隨後前後來了兩個事物:
事物B,事物ID=61,它執行sql將name 改爲jerry。
事物C,事物ID=62,它執行sql將name 改爲tom。
因而MySQL記錄下這樣一條新的undo log
你能夠看到,MySQL會將對一行數據的修改undo log經過DATA_ROLL_ID指針鏈接在一塊兒造成一個undo log鏈表鏈條。這樣事物C若是想回滾,他會將數據回滾到事物B修改後的狀態。而事物B想回滾他會將數據回滾到事物A的狀態。
在前面的文章中有專門的介紹:表空間、數據表、數據區、數據頁。
表空間、數據頁存在於物理層面。SQL想要修改的數據表、id=xxx的行都是邏輯上的。
而 undo log 幫你作的是邏輯上的數據回滾,而不是物理(數據頁)上是數據回滾。
其實在邏輯層和物理層都能回滾。
那,你有沒有想過爲何undo回滾的層面要設置在邏輯層而不是物理層的數據頁級別?
緣由你能夠這樣想:假如一個數據頁中存了300行數據,而你的update語句其實可能僅僅是更新了這個數據頁中的一行。可是數據庫可不必定是你本身在用!極可能有其餘的用戶也在使用而且修改了該數據頁中的另外200行。那這時若是你基於數據頁層面回滾,豈不是會將別人的不想回滾的數據給改錯?
在MySQL5.六、MySQL5.7版本中能夠經過innodb_undo_tablespaces
參數配置redo log表空間文件的個數,可是官網也有介紹這個參數在將來的MySQL版本中將會被廢棄,在MySQL8.0中初始化MySQL實例時會建立兩個默認的撤消表空間,而且可使用CREATE UNDO TABLESPACE
語法建立其餘撤消表空間 。
可是無論怎麼樣,若是你使用的是MySQL5.7仍是推薦使用這些參數以及開啓undo log的自動truncate。
參考:
《MySQL技術內幕》
https://dev.mysql.com/doc/refman/5.7/en/innodb-undo-logs.html
https://dev.mysql.com/doc/refman/5.7/en/innodb-undo-tablespaces.html
https://dev.mysql.com/doc/refman/5.7/en/glossary.html#glos_undo_tablespace
本文是第14篇,全文近100篇,點擊查看目錄