您當前的位置:首頁 > 旅遊

MySQL InnoDB MVCC實現

作者:由 溫正湖 發表于 旅遊時間:2018-07-20

注:本文由網易資料庫和大資料資深專家

蔣鴻翔

分享。原發表於其個人部落格 。

資料多版本(MVCC)是MySQL實現高效能的一個主要的一個主要方式,透過對普通的SELECT不加鎖,直接利用MVCC讀取指版本的值,避免了對資料重複加鎖的過程,今天我們就用最簡單的方式,來分析下MVCC具體的原理,先解釋幾個概念:

隱藏列

在分析MVCC原理之前,先看下InnoDB中資料行的結構:

MySQL InnoDB MVCC實現

在InnoDB中,每一行都有2個隱藏列DATA_TRX_ID和DATA_ROLL_PTR(如果沒有定義主鍵,則還有個隱藏主鍵列):

DATA_TRX_ID表示最近修改該行資料的事務ID

DATA_ROLL_PTR則表示指向該行回滾段的指標,該行上所有舊的版本,在undo中都透過連結串列的形式組織,而該值,正式指向undo中該行的

歷史記錄連結串列

整個MVCC的關鍵就是透過DATA_TRX_ID和DATA_ROLL_PTR這兩個隱藏列來實現的。

事務連結串列

MySQL中的事務在開始到提交這段過程中,都會被儲存到一個叫trx_sys的事務連結串列中,這是一個基本的連結串列結構:

MySQL InnoDB MVCC實現

事務連結串列中儲存的都是還未提交的事務,事務一旦被提交,則會被從事務連結串列中摘除。

ReadView

有了前面隱藏列和事務連結串列的基礎,接下去就可以構造MySQL實現MVCC的關鍵——ReadView。

ReadView說白了就是一個數據結構,在SQL開始的時候被建立。這個資料結構中包含了3個主要的成員:ReadView{

low_trx_id

, up_trx_id,

trx_ids

},在併發情況下,一個事務在啟動時,

trx_sys連結串列

中存在部分還未提交的事務,那麼哪些改變對當前事務是可見的,哪些又是不可見的,這個需要透過ReadView來進行判定,首先來看下ReadView中的3個成員各自代表的意思:

low_trx_id表示該SQL啟動時,當前事務連結串列中最大的事務id編號,也就是最近建立的除自身以外最大事務編號;

up_trx_id表示該SQL啟動時,當前事務連結串列中最小的事務id編號,也就是當前系統中建立最早但還未提交的事務;

trx_ids表示所有事務連結串列中事務的id集合。

上述3個成員組成了ReadView中的主要部分,簡單圖示如下:

MySQL InnoDB MVCC實現

根據上圖所示,所有資料行上DATA_TRX_ID小於up_trx_id的記錄,說明修改該行的事務在當前事務開啟之前都已經提交完成,所以對當前事務來說,都是可見的。而對於DATA_TRX_ID大於low_trx_id的記錄,說明修改該行記錄的事務在當前事務之後,所以對於當前事務來說是不可見的。

注意,ReadView是與SQL繫結的,而並不是事務,所以即使在同一個事務中,每次SQL啟動時構造的ReadView的up_trx_id和low_trx_id也都是不一樣的,至於DATA_TRX_ID大於low_trx_id本身出現也只有當多個SQL併發的時候,在一個SQL構造完ReadView之後,另外一個SQL修改了資料後又進行了提交,對於這種情況,資料其實是不可見的。

最後,至於位於(up_trx_id, low_trx_id)中間的事務是否可見,這個需要根據不同的事務隔離級別來確定。對於RC的事務隔離級別來說,對於事務執行過程中,已經提交的事務的資料,對當前事務是可見的,也就是說上述圖中,當前事務執行過程中,trx1~4中任意一個事務提交,對當前事務來說都是可見的;而對於RR隔離級別來說,事務啟動時,已經開始的事務連結串列中的事務的所有修改都是不可見的,所以在RR級別下,low_trx_id基本保持與up_trx_id相同的值即可。

最後用一張圖來解釋MySQL中的MVCC實現:

MySQL InnoDB MVCC實現

標簽: 事務  TRX  id  連結串列  ReadView