一致性讀檢視是InnoDB在實現MVCC用到的虛擬結構,用於讀提交(RC)和可重複度(RR)隔離級別的實現。
一致性檢視沒有物理結構,主要是在事務執行期間用來定義該事物可以看到什麼資料。
一、Read View
事務在正式啟動的時候我們會建立一致性檢視,該一致性檢視是基於整個庫的。
1、transaction id
InnodDB的每個事務都有一個唯一的事務ID,叫做transaction id,該ID在事務開始的時候向InnoDB申請,並且按照申請順序嚴格遞增。
每行資料都會有多個版本,每次事務更新資料的時候都會生成一個新的資料版本,並且把transaction id賦值給這個資料版本的事務id,稱為row trx_id。
上圖是一條行資料的多個版本,最新的版本是 V4。
其中U3、U2、U1代表的是undo log,V1、V2、V3在物理上並不真實存在,而是在需要的時候透過V4配合undo log計算獲得。
2、ReadView如何工作
ReadView中主要包含4個比較重要的內容:
- m_ids:表示在生成ReadView時當前系統中活躍的讀寫事務的事務id列表。
- min_trx_id:表示在生成ReadView時當前系統中活躍的讀寫事務中最小的事務id,也就是m_ids中的最小值。
- max_trx_id:表示生成ReadView時系統中應該分配給下一個事務的id值。
- creator_trx_id:表示生成該ReadView的事務的事務id。
在訪問某條記錄時,按照下邊的步驟判斷記錄的某個版本是否可見:
- 如果被訪問版本的trx_id屬性值與ReadView中的creator_trx_id值相同,意味著當前事務在訪問它自己修改過的記錄,所以該版本可以被當前事務訪問。
- 如果被訪問版本的trx_id屬性值小於ReadView中的min_trx_id值,表明生成該版本的事務在當前事務生成ReadView前已經提交,所以該版本可以被當前事務訪問。
- 如果被訪問版本的trx_id屬性值大於ReadView中的max_trx_id值,表明生成該版本的事務在當前事務生成ReadView後才開啟,所以該版本不可以被當前事務訪問。
- 如果被訪問版本的trx_id屬性值在ReadView的min_trx_id和max_trx_id之間,那就需要判斷一下trx_id屬性值是不是在m_ids列表中,如果在,說明建立ReadView時生成該版本的事務還是活躍的,該版本不可以被訪問;如果不在,說明建立ReadView時生成該版本的事務已經被提交,該版本可以被訪問。
3、記錄未提交的場景
如果某個版本的資料對當前事務不可見的話,那就順著版本鏈找到下一個版本的資料,繼續按照上邊的步驟判斷可見性,依此類推,直到版本鏈中的最後一個版本。
如果最後一個版本也不可見的話,那麼就意味著該條記錄對該事務完全不可見,查詢結果就不包含該記錄。
二、不同隔離級別下生成ReadView區別
在MySQL中,READ COMMITTED和REPEATABLE READ隔離級別的區別就是它們生成ReadView的時機不同。
1、可重複讀隔離
MySQL的預設隔離級別是RR(可重複讀),按照 可重複讀的語義,每個事務啟動的時候只能看到已經提交的事務,並且在本事務執行的過程中,不可以讀取到其他事務的更新操作。
在InnoDB 中,為每個事務構造了一個 當前事務ID陣列的快照,就是記錄事務開啟時,當前正在執行的事務ID 的集合。陣列裡面 trx_id 最小的記為 低水位,trx_id 最大的 + 1 記為高水位。如下圖所示:
對於一個新事務而言,所讀取到的記錄版本的 trx_id 可能有以下幾種情況:
1、在綠色區域:說明資料版本在事務開始前已提交,當前版本是可見的。
2、在紅色區域:說明資料版本在事務開始後變更的,當前版本是不可見的。
3、在橙色區域:包含 2 種情況。
A、如果 資料版本的 trx_id 在陣列中,說明是正在執行的事務,不可見。
B、如果 資料版本的 trx_id 不在陣列中,說明是已經提交的事務,可見。
可以看出,InnoDB 利用了 UndoLog 資料多版本的特點,實現了快速建立快照的能力。
2、讀已提交
對可重複讀來說,事務只有在第一次進行讀操作時才會生成一個ReadView,後續的讀操作都會重複使用這個ReadView。
也就是說,如果在此期間有其他事務提交了,那麼對於可重複讀來說也是不可見的,因為對它來說,事務活躍狀態在第一次進行讀操作時就已經確定下來,後面不會修改了。
對讀已提交來說,事務中的每次讀操作都會生成一個新的ReadView。
也就是說,如果這期間某個未提交事務Commit了,那麼它就會從ReadView中移除,新增到已提交事務中,這樣確保RC級別下事務每次讀操作都能讀到已經提交的資料。
參考資料:
《高效能 MySQL》第一章第 4 節;
極客時間《MySQL 實戰 45 講》