mysql多版本控制-MVCC
阿新 • • 發佈:2018-12-08
一、定義
多版本控制: 指的是一種提高併發的技術。最早的資料庫系統,只有讀讀之間可以併發,讀寫,寫讀,寫寫都要阻塞。引入多版本之後,只有寫寫之間相互阻塞,其他三種操作都可以並行,這樣大幅度提高了InnoDB的併發度。在內部實現中,與Postgres在資料行上實現多版本不同,InnoDB是在undolog中實現的,通過undolog可以找回資料的歷史版本。找回的資料歷史版本可以提供給使用者讀(按照隔離級別的定義,有些讀請求只能看到比較老的資料版本),也可以在回滾的時候覆蓋資料頁上的資料。在InnoDB內部中,會記錄一個全域性的活躍讀寫事務陣列,其主要用來判斷事務的可見性。
二、資料庫多版本讀場景
session 1 | session 2 |
---|---|
select a from test; return a = 10 | |
start transaction; | |
update test set a = 20; | |
start transaction; | |
select a from test; return ? | |
commit; | |
select a from test; return ? |
我們看下上面這個資料庫日常操作的例子。
- session 1修改了一條記錄,沒有提交;與此同時,session 2 來查詢這條記錄,這時候返回記錄應該是多少呢?
- session 1 提交之後 session 2 查詢出來的又應該是多少呢?
由於MySQL支援多種隔離級別,這個問題是需要看session2的事務隔離級別的,情況如下:
- 隔離級別為 READ-UNCOMMITTED 情況下:
session 1 commit前後 session 2 去檢視都會看到的是修改後的結果 a = 20 - 隔離級別為 READ-COMMITTED 情況下:
session 1 commit 前檢視到的還是 a =10 , commit之後看到的是 a = 20 - 隔離級別為 REPEATABLE-READ, SERIALIZABLE 情況下:
session 1 commit前後 session 2 去檢視都會看到的是修改後的結果 a = 10
其實不管隔離級別,我們也拋開資料庫中的ACID,我們思考一個問題:眾所周知,InnoDB的資料都是儲存在B-tree裡面的,修改後的資料到底要不要儲存在實際的B-tree葉子節點,session2是怎麼做到查詢出來的結果還是10,而不是20列?
三、MVCC實現原理
上述現象在資料庫中大家經常看到,但是資料庫到底是怎麼實現的,深究的人就不多了。
其實原理很簡單,資料庫就是通過UNDO和MVCC來實現的。
- 首先InnoDB每一行資料還有一個DB_ROLL_PT的回滾指標,用於指向該行修改前的上一個歷史版本
當插入的是一條新資料時,記錄上對應的回滾段指標為NULL
更新記錄時,原記錄將被放入到undo表空間中,並通過DB_ROLL_PT指向該記錄。session2查詢返回的未修改資料就是從這個undo中返回的。MySQL就是根據記錄上的回滾段指標及事務ID判斷記錄是否可見,如果不可見繼續按照DB_ROLL_PT繼續回溯查詢。
Read View的資料結構,它有三個部分:
- 當前活躍的事務列表
- Tmin ,就是活躍事務的最小值
- Tmax, 是系統中最大事務ID(不管事務是否提交)
具體的判斷流程如下:
- RR隔離級別下,在每個事務開始的時候,會將當前系統中的所有的活躍事務拷貝到一個列表中(read view)
- RC隔離級別下,在每個語句開始的時候,會將當前系統中的所有的活躍事務拷貝到一個列表中(read view)
並按照以下邏輯判斷事務的可見性。
四、MVCC解決了什麼問題
- MVCC使得資料庫讀不會對資料加鎖,select不會加鎖,提高了資料庫的併發處理能力
- 藉助MVCC,資料庫可以實現RC,RR等隔離級別,使用者可以檢視當前資料的前一個或者前幾個歷史版本。保證了ACID中的I-隔離性。
參考: