天天看點

MVCC多版本并發控制(Multi Version Concurrency Control)

快照讀和目前讀

  • 快照讀:讀取快照資料,有可能讀取到曆史版本資料,不加鎖的select就是快照讀
  • 目前讀:讀取最新版本的資料,讀取時保證其他事務不能修改目前記錄(要加鎖),加鎖的select、select for update、update、insert、delete等操作都是目前讀。

MVCC

  • MVCC其實是維持一個資料的多個版本,使得讀寫操作沒有沖突,這是一個理想的概念
  • MVCC解決讀寫阻塞,在讀操作時不阻塞寫操作,寫操作時也不阻塞讀操作
  • MVCC降低死鎖機率,采取樂觀鎖,讀取資料不加鎖,寫資料隻鎖定必要的行,是以會存在幻讀
  • MVCC解決一緻性讀,讀資料時讀取某個時間點的快照,隻能看到該時間點前送出的資料,看不到之後的資料
  • MVCC = MV + VC,MV就是通過Undo log來實作多版本管理,VC就是通過Read View來實作事務并發,針對不同的隔離級别,ReadView的機制不同,有RC和RR

實作原理

  • 依賴隐式字段、undo日志、Read View來實作

隐式字段

  • 每行資料,除了有自己定義的字段之外,還存在DB_TRX_ID,DB_ROLL_PTR,DB_ROW_ID等字段
  •  DB_TRX_ID,6位元組,最近使用該字段的事務的ID
  • DB_ROLL_PTR,7位元組,復原指針,指向這條記錄的上一個版本,建構連結清單
  • DB_ROW_ID,6位元組,隐含自增ID(主鍵)
  • 其實還有一個删除flag字段deleted_bit,被删除了不是真的删除,而是flag變了

undo日志

  • 分為兩種,分别是 insert undo log 和 update undo log,以連結清單的形式存在,next指針
  • insert undo log:事務在insert新紀錄時産生的undo log,在事務復原時需要使用,事務送出後馬上可以丢棄
  • update undo log:事務在update或者delete的時候産生undo log,在事務復原和快照讀的時候需要,不能随意删除(快照讀可能讀到update之前的資料),當事務送出時,将操作存入undo log,然後由Purge線程來操作是否删除(當操作的資料沒有事務在通路時,就可以删除undo log了)
  • Purge線程,專門清理delete_bit字段為true的記錄,purge線程也維護自己的ReadView(相當于最老舊的,可以删除的),當行delete_bit為true、事務id對ReadView可見,那麼删除

Read View

  • ReadView中主要就是有個清單來存儲系統中目前活躍着的讀寫事務,活躍的事務就是目前begin了,還沒有end的事務
  • 剛開始時,要進行查找的事務,根據自己的事務ID去查詢,在update undo log找到自己目前能通路的最新的行,然後拿出這行的事務id,利用這個id到ReadView的清單中去看看,目前最新的行是不是可見,可見就查,不可見的話就去找前一行
  • 分為兩種情況,分别是RC和RR兩種隔離級别下
  • RR級别,是要求和重複讀的,是以讀請求的時候,隻會在剛開始的時候讀取一次活躍事務拷貝到Read View中,然後接下來的讀都是複用這個ReadView
  • RC級别,是不要求重複讀的,是以每次讀請求的時候,都會将活躍事務拷貝到ReadView中
  • 在Read View中怎麼查呢?比如目前清單中活躍事務是[80,100]
  1. 如果你要通路的記錄版本的事務id為50,比目前清單最小的id80小,那說明這個事務在之前就送出了,是以對目前活動的事務來說是可通路的。
  2. 如果你要通路的記錄版本的事務id為70,發現此事務在清單id最大值和最小值之間,那就再判斷一下是否在清單内,如果在那就說明此事務還未送出,是以版本不能被通路。如果不在那說明事務已經送出,是以版本可以被通路。
  3. 如果你要通路的記錄版本的事務id為110,那比事務清單最大id100都大,那說明這個版本是在ReadView生成之後才發生的,是以不能被通路。