淺談MySQL:MVCC的作用及原理


什么是MVCC

MVCC全稱是Multi-Version Concurrency Control,即多版本並發控制,主要是為了提高數據庫的並發讀寫性能。

當我們並發讀寫同一行數據的時候,為了防止出錯,需要對數據進行加鎖操作,但這並不是一個高效的操作,很容易造成操作請求阻塞超時。而MVCC采用了更好的方式去處理並發讀寫請求,做到在發生讀寫請求沖突時不用加鎖。這個讀是指的快照讀,而不是當前讀。

那么什么是當前讀,什么又是快照讀?我們下面來學習一下。

當前讀

當前讀就是讀取數據庫記錄的最新版本,會對當前讀取的數據進行加鎖,防止其他事務修改數據,是悲觀鎖的一種操作。

以下幾種情況是當前讀:

  • select 語句加鎖是當前讀

    # 共享鎖
    select a from t where id = 1 lock in share mode;
    
    #排他鎖
    select a from t where id = 1 for update;
    
  • update 語句是當前讀

    update t set a = a + 1;
    

快照讀

快照讀的實現是基於多版本並發控制,即MVCC,快照讀讀到的數據不一定是當前最新的數據,有可能是之前歷史版本的數據。

以下幾種情況是快照讀:

  • 在默認隔離級別下,select 語句默認是快照讀

    select a from t where id = 1;
    

快照讀與MVCC的關系

MVCC是”維持一個數據的多個版本,使讀寫操作沒有沖突”的一個抽象概念。

這個概念需要具體功能去實現,這個具體實現就是快照讀。

MVCC解決並發哪些問題

MVCC用來解決讀-寫沖突的無鎖並發控制,就是為事務分配單向增長的時間戳。為每個數據修改保存一個版本,版本與事務時間戳相關聯。讀操作只讀取該事務開始前的數據庫快照。

解決問題如下:

  • 並發讀-寫時:可以做到讀操作不阻塞寫操作,同時寫操作也不會阻塞讀操作。

  • 解決臟讀、幻讀、不可重復讀等事務隔離問題,但不能解決寫-寫更新丟失問題。因此需要下面提高並發性能的組合:

    • MVCC + 悲觀鎖:MVCC解決讀寫沖突,悲觀鎖解決寫寫沖突
    • MVCC + 樂觀鎖:MVCC解決讀寫沖突,樂觀鎖解決寫寫沖突

MVCC的實現原理

MVCC主要是版本鏈,undo日志 ,Read View 來實現的

版本鏈 & undo日志

我們數據庫中的每行數據都有如下幾個隱藏字段:

字段名 占用空間 說明
trx_id 6byte 最近修改(修改/插入)事務ID:記錄創建這條記錄/最后一次修改該記錄的事務ID
roll_pointer 7byte 回滾指針,指向這條記錄的上一個版本(存儲於rollback segment里)
row_id 6byte 隱含的自增ID(隱藏主鍵),如果數據表沒有主鍵,InnoDB會自動以db_row_id產生一個聚簇索引

版本鏈的結構如下圖所示,每次修改都會在這個鏈條后面增加一個版本,trx_id就代表最新這條記錄的ID。而歷史數據都會被存入undo日志,通過回滾指針roll_pointer可以找到數據行的前一個版本,以供事務回滾時使用。
image

Read View

事務進行快照讀操作的時候生產的讀視圖(Read View),在該事務執行快照讀的那一刻,會生成數據庫系統當前的一個快照。通過Read View,事務可以判斷版本鏈中的哪個版本是可用的。

Read View中保存的字段信息如下:

字段名 說明
m_ids 表示在生成Read View時,當前系統中活躍的讀寫事務的事務ID列表
min_trx_id 表示在生成Read View時,當前系統中活躍的讀寫事務中最小的事務ID,也就是m_ids中的最小值
max_trx_id 表示生成Read View時,系統中應該分配給下一個事務的ID值
creator_trx_id 表示生成該Read View的事務的事務ID

那么Read View是如何判斷版本鏈中的哪個版本是可用的呢?通過以下4個條件就可以判斷:

  • trx_id == creator_trx_id:可以訪問這個版本
  • trx_id < min_trx_id:可以訪問這個版本
  • trx_id > max_trx_id:不可以訪問這個版本
  • min_trx_id <= trx_id <= max_trx_id:如果trx_idm_ids中是不可以訪問這個版本的,反之可以訪問

MVCC如何實現RC和RR

我們在上一篇中講過RC(Read Committed,讀提交)和RR(Repeatable Read,可重復讀)隔離級別的定義,這兩個隔離級別的實現都離不開MVCC。

RR、RC生成Read View的時機

  • RC隔離級別下,每個快照讀都會生成並獲取最新的Read View,因此可能出現在同一個事務中兩次查詢的結果不一致的情況
  • RR隔離級別下,則是同一個事務中的第一個快照讀才會創建Read View,之后的快照讀獲取的都是同一個Read View,之后的查詢就不會重復生成了,所以一個事務的查詢結果每次都是一樣的

解決幻讀問題

  • 快照讀:通過MVCC來進行控制的,不用加鎖。按照MVCC中規定的“語法”進行增刪改查等操作,以避免幻讀。
  • 當前讀:通過next-key鎖(行鎖+gap鎖)來解決問題的。

總結

從以上的描述中,我們可以看出MVCC指的就是在使用RC、RR這兩種隔離級別的事務在執行普通的SEELCT操作時訪問記錄的版本鏈的過程,MVCC可以使不同事務的讀-寫、寫-讀操作並發執行,從而提升系統性能。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM