一、概述
MVCC(Multiversion Concurrency Control),即多版本並發控制。它使得大部分支持行鎖的事務引擎,不再單純的使用行鎖來進行數據庫的並發控制,取而代之的是,把數據庫的行鎖與行的多個版本結合起來,只需要很小的開銷,就可以實現非鎖定讀,從而大大提高數據庫系統的並發性能。
二、MVCC的目的
使用MVCC的目的在於降低開銷。
鎖機制可以控制並發操作,但是其系統開銷較大,而MVCC可以在大多數情況下代替行級鎖,使用MVCC能降低其系統開銷。
實際上,大多數的MYSQL事務型存儲引擎,如InnoDB,Falcon都不僅僅使用簡單的行鎖機制,而是和MVCC–多版本並發控制來一起使用。
三、MVCC原理
MVCC可以提供基於某個時間點的快照,使得對於事務看來,總是可以提供與事務開始時刻相一致的數據,而不管這個事務執行的時間有多長。所以在不同的事務看來,同一時刻看到的相同行的數據可能是不一樣的,即一個行可能有多個版本。
四、MVCC具體實現
InnoDB的MVCC,是通過在每行記錄后面保存兩個隱藏的列來實現的,這兩個列,其中一列存儲行被創建的“時間”,另外一列存儲行被刪除的“時間”。這里的“時間”並不是實際的時間值,而是系統版本號(可以理解為事務的ID),每當一個事務開始的時候,innodb都會給這個事務分配一個遞增的版本號,所以版本號也可以被認為是事務號。
在repeated read的隔離級別下,具體各種數據庫操作的實現:
1.select:滿足以下兩個條件innodb會返回該行數據:
(1)該行的創建版本號小於等於當前版本號,用於保證在select操作之前所有的操作已經執行落地。
(2)該行的刪除版本號大於當前版本或者為空。刪除版本號大於當前版本意味着有一個並發事務將該行刪除了。
2. insert:將新插入的行的創建版本號設置為當前系統的版本號。
3.delete:將要刪除的行的刪除版本號設置為當前系統的版本號。
4.update:不執行原地update,而是轉換成insert + delete。將舊行的刪除版本號設置為當前版本號,並將新行insert同時設置創建版本號為當前版本號。
以上4條,寫操作(insert、delete和update)執行時,需要將系統版本號遞增。
五、例子
5.1 insertbegin;
INSERT INTO user(username) VALUES('jack');
INSERT INTO user(username) VALUES('hello');
commit;
插入兩條數據,假設事務ID(系統版本號)為1,則創建時間列的值為1。
id
username
創建時間
刪除時間
1
jack
1
undefined
2
hello
1
undefined
注:后面兩列(創建時間、刪除時間)是隱藏列,並不能看見,這里是示意圖。
5.2 deleteDELETE FROM user WHERE id=1;
刪除操作的時候,把事務版本號作為刪除版本號,此時為2.
id
username
創建時間
刪除時間
1
jack
1
2
2
hello
1
undefined
5.3 updateUPDATE user SET username='world' WHERE id=2;
不執行update,而是轉換成insert + delete,先標記舊的那行記錄為已刪除,並且刪除版本號是事務版本號,然后插入一行新的記錄的方式。事務ID為3。
id
username
創建時間
刪除時間
1
jack
1
2
2
hello
1
3
2
world
3
undefined
5.4 selectSELECT * FROM user
當前版本號為4,所以按照select的兩個條件返回結果如下:
id
username
創建時間
刪除時間
2
world
3
undefined
5.5 綜合示例
下面來看一個綜合一點的例子:有兩個事務,事務ID分別為5,6。
事務5:SELECT * FROM user WHERE id=2;
事務6:UPDATE user SET username='Tom' WHERE id=2;
假設事務5還未執行完畢,而事務6已經執行完畢,此時表中數據為:
id
username
創建時間
刪除時間
1
jack
1
2
2
hello
1
3
2
world
3
6
2
Tom
6
undefined
然后事務5執行完畢,因為username=Tom那行的創建時間6>當前版本號5,而username=world那行的創建時間3>當前版本號>刪除時間,由select的兩個條件,得到的結果為:
id
username
創建時間
刪除時間
2
world
3
6
從上面這個例子我們可以簡單地理解下MVCC如何代替鎖的(並不准確)。
如果使用鎖,上面的操作如何進行?首先,事務5占用鎖並執行,事務6阻塞,事務5執行完畢后得到查詢結果並釋放鎖,事務6得到鎖並執行自身的update操作。整個過程使用鎖機制控制並發操作,但是其系統開銷較大。
而使用MVCC,通過版本檢查,只獲得自己需要的數據版本。我們不需要承擔鎖機制的開銷,卻能達到同樣的效果。
六、MVCC的優缺點
優點:降低其系統開銷。在讀取數據的時候,innodb幾乎不用獲得任何鎖,每個查詢都通過版本檢查,只獲得自己需要的數據版本,從而大大提高了系統的並發度。
缺點:為了實現多版本,innodb必須對每行增加相應的字段來存儲版本信息,同時需要維護每一行的版本信息,而且在檢索行的時候,需要進行版本的比較,因而降低了查詢的效率;innodb還必須定期清理不再需要的行版本,及時回收空間,這也增加了一些開銷。
參考資料