對Innodb中MVCC的理解
阿新 • • 發佈:2021-02-20
一、什麼是MVCC
MVCC (Multiversion Concurrency Control) 中文全程叫多版本併發控制,是現代資料庫(如MySql)引擎實現中常用的處理讀寫衝突的手段,目的在於提高資料庫高併發場景下的吞吐效能。 MySQL的InnoDB儲存引擎預設事務隔離級別是RR(可重複讀),是通過 "行級鎖+MVCC"一起實現的,正常讀的時候不加鎖,寫的時候加鎖。而 MCVV 的實現依賴:隱藏欄位、Read View、Undo log。 另外MVCC只在 Read Committed 和 Repeatable Read兩個隔離級別下工作,其他兩個隔離級別和MVCC不相容:- Read Uncommitted總是讀取最新的記錄行,不需要MVCC的支援;
- Serializable 則會對所有讀取的記錄行都加鎖,單靠MVCC無法完成。
二、MVCC實現的核心知識點
1、事務版本號 每次事務開啟前都會從資料庫獲得一個自增長的事務ID,可以從事務ID判斷事務的執行先後順序。 可以通過這樣的命令來檢視:select TRX_ID from INFORMATION_SCHEMA.INNODB_TRX; 2、隱藏欄位(Innodb 為每行額外添加了3個欄位,具體請參考官方文件): DB_TRX_ID:大小為6個位元組。指插入或更新該行的最後一個事務的事務識別符號,也就是事務ID。 此外,刪除在內部被視為更新,在該更新中,該行中的特殊位被設定為將其標記為已刪除。 DB_ROLL_PTR:大小為7個位元組。表示指向該行回滾段的指標。 回滾指標指向寫入回滾段的撤消日誌記錄。 如果行已更新,則撤消日誌記錄將包含在更新行之前重建行內容所必需的資訊。 DB_ROW_ID:大小為6個位元組。包含一個行ID,該行ID隨著插入新行而單調增加。 如果InnoDB自動生成聚集索引,則該索引包含行ID值。 否則,DB_ROW_ID列不會出現在任何索引中。三、案例分析
下面通過案例來分析MVCC怎麼實現一致性讀取的。前期資料準備:- 使用預設隔離級別RR;
- 建立一個表: create table test(id int AUTO_INCREMENT, score int, primary key(id)) AUTO_INCREMENT = 0;
- 假設當前事務id已經自增長到100;
步驟 | 事務1 | 事務2 | 事務3 |
1 | begin; | ||
2 | begin; | ||
3 | insert into test(score) select 101; 此時事務ID為101 | ||
4 | insert into test(score) select 102; 此時事務ID為102 | ||
5 | select * from test; +----+-------+ | id | score | +----+-------+ | 1 | 101 | +----+-------+ 此時就會建立read view: up_limit_id = 101 low_limit_id = 103 trx_ids為(101,102) 而101自身可見,102在活躍事務列表中不可見 | ||
6 | insert into test(score) select 103; 此時事務ID為103 | ||
7 | insert into test(score) select 104; 此時事務ID為104 | ||
8 | nsert into test(score) select 105; 此時事務ID為105 | ||
9 | select * from test; +----+-------+ | id | score | +----+-------+ | 3 | 103 | | 4 | 104 | | 5 | 105 | +----+-------+ 此時的up_limit_id=101, low_limit_id=106, trx_ids為(101, 102), 而101和102在trx_ds列表中不可見 | ||
10 | select * from test; +----+-------+ | id | score | +----+-------+ | 2 | 102 | | 3 | 103 | | 4 | 104 | | 5 | 105 | +----+-------+ 此時就會建立read view: up_limit_id=101, low_limit_id=106, trx_ids為(101, 102), 102自身可見,101在活躍事務列表中不可見 而103、104、105不在trx_ids列表中所有可見 | ||
11 | select * from test; +----+-------+ | id | score | +----+-------+ | 1 | 101 | | 3 | 103 | | 4 | 104 | | 5 | 105 | +----+-------+ 由於事務內read view不變 (與RC的區別就在這), 此時的up_limit_id=101,low_limit_id=103, trx_ids為(101, 102), 101自身可見,102在活躍事務列表中不可見 而>=103的都不可見 |