(轉載)MySQL InnoDB 的多版本併發控制(MVCC)

原文地址:https://www.imooc.com/article/details/id/31277

innoDB 的多版本併發控制(MVCC)

1. MVCC定義

1.1定義

MVCC全稱Mutli Version Concurreny Control,多版本併發控制,也可稱之爲一致性非鎖定讀;它通過行的多版本控制方式來讀取當前執行時間數據庫中的行數據。實質上使用的是快照數據,這樣就可以實現不加鎖讀。MVCC 主要應用於 Read Commited  和 Repeatable read  兩個事務隔離級別。

1.2一些困惑

  • MYSQL的事務隔離級中的RC,RR級別怎麼實現?

  • 事務回滾操作是怎麼回滾?

  • 數據多版本併發控制中的多版本在哪裏?

2.innoDB 的邏輯存儲結構

innoDB 的數據保存在表空間中,表空間又包含各種段,其中有數據段,索引段,回滾段。InnoDB中數據以B+Tree的數據結構存儲的,非葉子節點既是索引,葉子節點既是數據行,回滾段用於存儲undoLog,undoLog中記錄的就是多版本數據,用於快照讀和事務失敗後的數據回滾,MySQL在合適的時機會清理undoLog。

 

960295-20180123215304569-1124033252.png

3.MVCC的實現

MVCC的實現依賴於 每行的隱藏字段,DB_TRX_ID,DB_ROLL_PTR,刪除標記位,還有read_view。

3.1 三個隱藏字段

innoDB 向數據庫中存儲的每行添加三個隱藏字段(有的書上說是兩個,但是我看官方文檔說是三個)。

數據初始化.png

DB_TRX_ID 事務id

佔6 字節,表示這一行數據最後插入或修改的事務id。此外刪除在內部也被當作一次更新,在行的特殊位置添加一個刪除標記(記錄頭信息有一個字節存儲是否刪除的標記)。

DB_ROLL_PTR  回滾指針

佔7字節,回滾指針指向被寫在Rollback segment中的undoLog記錄,在該行數據被更新的時候,undoLog 會記錄該行修改前內容到undoLog。

DB_ROW_ID  行ID

佔7字節,他就項自增主鍵一樣隨着插入新數據自增。如果表中不存主鍵 或者 唯一索引,那麼數據庫 就會採用DB_ROW_ID生成聚簇索引。否則DB_ROW_ID不會出現在索引中。

3.2 undo log

undo log是爲回滾而用,具體內容就是copy事務前的數據庫內容(行)到undo buffer,在適合的時間把undo buffer中的內容刷新到磁盤。undo buffer與redo buffer一樣,也是環形緩衝,但當緩衝滿的時候,undo buffer中的內容會也會被刷新到磁盤;與redo log不同的是,磁盤上不存在單獨的undo log文件,所有的undo log均存放在主ibd數據文件中(表空間),即使客戶端設置了每表一個數據文件也是如此。

undo log 在 Rollback segment中又被細分爲 insert  和 update undo log , insert 類型的undo log 僅僅用於事務回滾,當事務一旦提交,insert undo log 就會被丟棄。update的undo log 被用於 一致性的讀和事務回滾,update undo log 的清理 是在 沒有事務 需要對這部分數據快照進行一致性讀的時候 進行清理。

undo log 的創建
每次對數據進行更新操作時,都會copy 當前數據,保存到undo log 中。並修改 當前行的 回滾指針指向 undo log 中的 舊數據行。

 

undolog.png

3.3 read_view 判斷數據行可見性

在innodb中,創建一個新事務的時候,innodb會將當前系統中的活躍事務列表創建一個副本(read view),副本中保存的是系統當前不應該被本事務看到的其他事務id列表。當用戶在這個事務中要讀取該行記錄的時候,innodb會將該行當前的版本號與該read view進行比較。

具體的算法是(可重複讀級別):

假設當前 數據行 事務ID 爲 T0 ,read view 中保存的 最老的事務id T_min ,最新的 事務id 爲 T_max,當前進行的事務id 爲 T_new 。

  • 如果 T0 < T_min ,那麼該行數據可見。

    因爲 T0 在 T_new 事務開始前 已經提交。

  • 如果 T0 > T_max ,數據行不可見。根據DB_ROLL_PTR 指針 找到下一個 數據版本,再次進行數據可見性判斷。

    因爲 T0事務 在 T_new 開始前並不存在,也就是說T0 在T_new 開始後 創建。

  • 如果 T_min <= T0 <= T_max ,判斷T0 是否在read_view 中,如果 不在該行數據可見。如果不可見根據DB_ROLL_PTR 指針 找到下一個 數據版本,再次進行數據可見性判斷。

3.4 Read Commited  ,Repeatable read 數據可見性判斷

Read Commited 和 Repeatable read 採用相同的數據可見性判斷邏輯。
那麼怎麼在相同的判斷邏輯下 分別 實現 RC 和 RR 級別的?

  • Read Commited
    在每次語句執行的過程中,都關閉read_view, 重新創建當前的一份新的read_view。
    這樣就可以根據當前的全局事務鏈表創建read_view的事務區間,實現read committed隔離級別。

  • Repeatable read
    在repeatable read的隔離級別下,創建事務trx結構的時候,就生成了當前的global read view。
    使用trx_assign_read_view函數創建,一直維持到事務結束,這樣就實現了repeatable read隔離級別。

正是因爲Read Commited和 Repeatable read的read view 生成方式和時機不同,導致在不同隔離級別下,read committed 總是讀最新一份快照數據,而repeatable read 讀事務開始時的行數據版本。

4. 新的疑問

每行的記錄頭信息保存在什麼位置,官方文檔說是刪除是邏輯的刪除,刪除只是記錄一個刪除標記。
通過查看一些博客說是被記錄在記錄頭信息中,但是官方說的三個隱藏字段並沒有提到這個記錄頭信息。那他到底算不算隱藏字段。如果不是隱藏字段那他記錄在哪裏?

 

1253350-20180420172417526-524213118.jpg


作者:牛魔王的故事
鏈接:https://www.imooc.com/article/details/id/31277
來源:慕課網

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章