InnoDB MVCC實現原理及原始碼解析

yzs87發表於2018-04-15

1、原理介紹

資料多版本(MVCC)是MySQL實現高效能的一個主要的一個主要方式,透過對普通的SELECT不加鎖,直接利用MVCC讀取指版本的值,避免了對資料重複加鎖的過程。InnoDB支援MVCC多版本,其中RC和RR隔離級別是利用consistent read view方式支援的,即在某個時刻對事物系統打快照記下所有活躍讀寫事務ID,之後讀操作根據事務ID與快照中的事務ID進行比較,判斷可見性。

2、InnoDB資料行結構

行結構中,除了使用者定義的列外還有3個系統列:DATA_ROW_ID、DATA_TRX_ID、DATA_ROLL_PTR,如果表沒有定義主鍵那麼DATA_ROW_ID作為主鍵列,否則行結構中沒有DATA_ROW_ID列。其中:

    DATA_TRX_ID:修改該行資料的事務的ID

    DATA_ROLL_PTR:指向該行回滾段的指標。

整個MVCC實現,關鍵靠這2個欄位來完成。

3、READ-VIEW原理流程


4、READ-VIEW解讀

1)read view是和SQL語句繫結的,在每個SQL語句執行前申請或獲取(RR隔離級別:事務第一個select申請,之後都用這個;RC隔離級別:每個select都會申請)

2)read view結構


點選(此處)摺疊或開啟

  1. struct read_view_t{
  2.     ulint type; /*!< VIEW_NORMAL, VIEW_HIGH_GRANULARITY */
  3.     undo_no_t undo_no;/*!< 0 or if type is
  4.                 VIEW_HIGH_GRANULARITY
  5.                 transaction undo_no when this high-granularity
  6.                 consistent read view was created */
  7.     trx_id_t low_limit_no;
  8.                 /*!< The view does not need to see the undo
  9.                 logs for transactions whose transaction number
  10.                 is strictly smaller (<) than this value: they
  11.                 can be removed in purge if not needed by other
  12.                 views */
  13.     trx_id_t low_limit_id;
  14.                 /*!< The read should not see any transaction
  15.                 with trx id >= this value. In other words,
  16.                 this is the "high water mark". */
  17.     trx_id_t up_limit_id;
  18.                 /*!< The read should see all trx ids which
  19.                 are strictly smaller (<) than this value.
  20.                 In other words,
  21.                 this is the "low water mark". */
  22.     ulint n_trx_ids;
  23.                 /*!< Number of cells in the trx_ids array */
  24.     trx_id_t* trx_ids;/*!< Additional trx ids which the read should
  25.                 not see: typically, these are the read-write
  26.                 active transactions at the time when the read
  27.                 is serialized, except the reading transaction
  28.                 itself; the trx ids in this array are in a
  29.                 descending order. These trx_ids should be
  30.                 between the "low" and "high" water marks,
  31.                 that is, up_limit_id and low_limit_id. */
  32.     trx_id_t creator_trx_id;
  33.                 /*!< trx id of creating transaction, or
  34.                 0 used in purge */
  35.     UT_LIST_NODE_T(read_view_t) view_list;
  36.                 /*!< List of read views in trx_sys */
  37. };

主要包括3個成員{low_limit_id,up_limit_id,trx_ids}。

    low_limit_id:表示建立read view時,當前事務活躍讀寫連結串列最大的事務ID,即最近建立的除自身外最大的事務ID

    up_limit_id:表示建立read view時,當前事務活躍讀寫連結串列最小的事務ID。

    trx_ids:建立read view時,活躍事務連結串列裡所有事務ID

3)對於小於等於RC的隔離級別,每次SQL語句結束後都會呼叫read_view_close_for_mysql將read view從事務中刪除,這樣在下一個SQL語句啟動時,會判斷trx->read_view為NULL,從而重新申請。對於RR隔離級別,則SQL語句結束後不會刪除read_view,從而下一個SQL語句時,使用上次申請的,這樣保證事務中的read view都一樣,從而實現可重複讀的隔離級別。

4)對於可見性判斷,分配聚集索引和二級索引。聚集索引:

     記錄的DATA_TRX_ID < view->up_limit_id:在建立read view時,修改該記錄的事務已提交,該記錄可見

   DATA_TRX_ID >= view->low_limit_id:當前事務啟動後被修改,該記錄不可見

   DATA_TRX_ID 位於(view->up_limit_id,view->low_limit_id):需要在活躍讀寫事務陣列查詢trx_id是否存在,如果存在,記錄對於當前read view是不可見的。

   二級索引:

    由於InnoDB的二級索引只儲存page最後更新的trx_id,當利用二級索引進行查詢的時候,如果page的trx_id小於view->up_limit_id,可以直接判斷page的所有記錄對於當前view是可見的,否則需要回clustered索引進行判斷。

5)如果記錄對於view不可見,需要透過記錄的DB_ROLL_PTR指標遍歷history list構造當前view可見版本資料

6)start transaction和begin語句執行後並沒有在innodb層分配事務ID、回滾段、read_view、將事務放到讀寫事務連結串列等,這個操作需要第一個SQL語句呼叫函式trx_start_low來完成,這個需要注意。



來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/31493717/viewspace-2152957/,如需轉載,請註明出處,否則將追究法律責任。

相關文章