咱們知道innodb 支撐事務。那麼事務其中一個功能是須要支持回滾。
事務中可能設計到增,刪,改等操做。那麼回滾如和實現呢?sql
undo log 就是記錄這些用於回滾的信息。
那麼MVCC 爲何也是靠undo log來實現的呢?
也許你據說過聚簇索引每條記錄有個隱藏字段叫row_id
,他的做用是若是不指定主鍵,它就變成了系統內部的自增主鍵。同時其實每條記錄還有兩個字段一個是trx_id
,一個是roll_pointer
.這個兩個字段就是用來實現MVCC功能。shell
trx_id
: 修改當前記錄的事務id。roll_pointer
:只向一個undo log。每一條undo log記錄固然也有trx_id, 和roll_pointer字段。服務器
CREATE TABLE `student` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`name` varchar(255) NOT NULL,
`age` int(11) NOT NULL,
`addresss` varchar(255) NOT NULL DEFAULT '',
PRIMARY KEY (`id`),
KEY `index_age` (`age`) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=0 DEFAULT CHARSET=utf8;
INSERT student VALUES (1,'張一',1,'ssss'),(2,'張二',2,'ssss');
複製代碼
聚簇索引內容相似於一下:spa
id | name | age | address | trx_id | roll_pointer |
---|---|---|---|---|---|
1 | 張一 | 1 | ssss | 10 | insert_undo_log 地址 |
2 | 張二 | 2 | ssss | 10 | insert_undo_log 地址 |
undo log相似於一下:設計
id | name | age | address | trx_id | roll_pointer | undo id |
---|---|---|---|---|---|---|
1 | 張一 | 1 | ssss | 10 | 空 | 0 |
2 | 張二 | 2 | ssss | 10 | 空 | 1 |
undo id 的在同一個事務中依次遞增的。code
update set age=10 where id = 1; #更新語句一
update set age=20 where id = 1; #更新語句二
複製代碼
id | name | age | address | trx_id | roll_pointer | undo id |
---|---|---|---|---|---|---|
1 | 張一 | 1 | ssss | 20 | 指向上一條insert log 地址 | 0 |
1 | 張一 | 10 | ssss | 21 | 上一條undo log 地址 | 0 |
幾點說明:索引
信息結構要複雜的多
,會分更新主鍵,和不更新主鍵
的狀況。這裏不詳細展開。在MYSQL 5.6 以後,能夠爲undo log 分配獨立的表空間。
默認表空間的數量爲2個,能夠設置innodb_undo_tablespaces 來增長數量。
每一個表空間又被分爲多個回滾段(rollback segment),回滾段的數量能夠查看innodb_undo_logs。
每一個回滾段就存放了undo log 頁。
若是undo log 對應的事務都已是執行完畢,或者回滾結束的。那麼對應的undo log 空間就能夠被回收了。
假設有一個長事務,遲遲未被提交,或回滾,那麼undo log 會愈來愈大。嚴重的會直接致使服務器磁盤空間爆滿。因此若是忽然服務器磁盤空間使用量快速上升,也能夠查看下是否有長事務沒有提交,致使undo log佔用很大磁盤空間。事務
undo log 兩大做用:innodb
保障事務的原子性
。事務中的全部更新語句,要麼全被執行,要麼全被回滾。經過將同一個trx_id 的undo log 就能夠實現回滾同一事務的全部更新語句了。