MySQL MVCC介紹
MVCC是什麼?
MVCC的全稱是Multi-Version Concurrency Control,通常用於資料庫等場景中,實現多版本的併發控制
Multiversion concurrency control (MCC or MVCC), is a concurrency control method commonly used by database management systems to provide concurrent access to the database and in programming languages to implement transactional memory.
如果沒有併發控制,那麼如果同時有使用者讀寫資料,那麼可能出現讀出的資料不一致的情況。比如說,進行銀行賬戶A到B的轉賬,當A賬戶的錢被扣掉,而錢還沒有加到B賬戶,此時使用者檢視自己的餘額,會感覺錢憑空消失了。MySQL的隔離性就是用來解決這類問題的,而隔離性是透過不同的併發控制手段來實現的。對於剛才的問題,一種簡單的併發控制方式,就是講讀寫操作序列化,在賬戶間轉賬時,不允許查詢賬戶,雖然這種方式可以解決問題,但無疑過於簡單粗暴,效率極低。相比於序列化的併發控制,MVCC的優勢在於讀寫影響,對於現代網際網路讀多寫少的場景,這種方式效能明顯更高。
MVCC是透過儲存資料的多個版本來實現併發控制,當需要更新某條資料時,實現了MVCC的儲存系統不會立即用新資料覆蓋原始資料,而是建立該條記錄的一個新的版本。對於多數資料庫系統,儲存會分為Data Part和Undo Log,Data Part用來儲存事務已提交的資料,而Undo Log用來儲存舊版本的資料。多版本的存在允許了讀和寫的分離,讀操作是需要讀取某個版本之前的資料即可,和寫操作不衝突,大大提高了效能。
每條記錄在更新的時候都會同時記錄一條回滾操作。同一條記錄在系統中可以存在多個版本,這就是資料庫的多版本併發控制。(MVCC)。
MVCC的效果
假如MVCC是按照時間來判定資料的版本,在Time=1的時刻,資料庫的狀態如下:
Time Record A Record B
“Record A When time=0” “Record B when time=0”
1 “Record A When time=1”
這個時候系統中實際儲存了三條記錄,Record A在時間0和1的各一條記錄,Record B的一條記錄,如果一個事務在Time=0的時刻開啟,那麼讀到的資料是:
Record A Record B
“Record A When time=0” “Record B when time=0”
如果這個事務在Time=1的時候開啟,那麼讀到的資料是:
Record A Record B
“Record A When time=1” “Record B when time=0”
上面的Case可以看到,對於讀來講,事務只能讀到某一個版本及這個版本之前的最新一條資料,假如在Time=2的時候,事務Transaction X要插入Record C,並更新Record B,
但事務還未提交,那麼資料庫的狀態如下:
Time Record A Record B Record C
“Record A When time=0” “Record B when time=0”
1 “Record A When time=1”
2(Not Committed) “Record B when time=2” “Record C When time=2”
這時候其它事務會讀到的是什麼了?在這個情況下,其它讀事務所能看到系統的最新版本是系統處於Time=1的時候,所以依然不會讀到Transaction X所改寫的資料,此時讀到的資料依然為:
Record A Record B
“Record A When time=1” “Record B when time=0”
基於這種版本機制,就不會出現另一個事務讀取時,出現讀到Record C而Record B還未被Transaction X更新的中間結果,因為其它事務所看到的系統依然處於Time=1的狀態。
至於說,每個事務應該看到具體什麼版本的資料,這個是由不同系統的MVCC實現來決定的,下文我會介紹MySQL的MVCC實現。除了讀到的資料必須小於等於當前系統已提交的版本外,寫事務在
提交時必須大於當前的版本,而這裡如果想想還會有一個問題,如果Time=2的時刻,開啟了多個寫或更新事務,當它們同時嘗試提交時,必然會有一個事務發現資料庫已經處於Time=2的狀態了,
那麼這個事務該怎麼辦了?大家可以好好想想。
MySQL的MVCC
MySQL的Innodb引擎支援多種事務隔離級別,而其中的RR級別(Repeatable-Read)就是依靠MVCC來實現的,MySQL中MVCC的版本指的是事務ID(Transaction ID),首先來看一下MySQL Innodb中行記錄
的儲存格式,除了最基本的行資訊外,還會有一些額外的欄位,這裡主要介紹和MVCC有關的欄位:DATA_TRX_ID和DATA_ROLL_PTR,如下是一張表的初始資訊:
Primary Key Time Name DATA_TRX_ID DATA_ROLL_PTR
1 2018-4-28 Huan 1 NULL
這裡面為了便於說明,表中DATA_TRX_ID和DATA_ROLL_PTR存的值是Mock的值:
DATA_TRX_ID:最近更新這條記錄的Transaction ID,資料庫每開啟一個事務,事務ID都會增加,每個事務拿到的ID都不一樣
DATA_ROLL_PTR:用來儲存指向Undo Log中舊版本資料指標,支援了事務的回滾
最開始的記錄無法回滾,所以DATA_ROLL_PTR為空。
這個時候開啟事務A(事務ID:2),對記錄進行了更新,但還沒有提交,那麼當前的資料為:
Transaction 1
可以看到,舊的資料會被存到Undo Log中,透過當前記錄中的DATA_ROLL_PTR關聯,那麼如果另一個事務中想讀取該資料,讀到的會是什麼資料了?假如說另一個事務B在事務A之後開啟(事務ID:3),
既然我們最開始說Innodb的MVCC是基於事務ID做的,那麼既然事務B的事務ID比事務A的大,那麼事務B就可以獨到A還未提交的資料了,這明顯和Innodb RR的定義不符合。實際上,事務讀取時,
判斷應該讀取哪個版本的記錄,有一個較為複雜的邏輯,不是單純的和記錄上的事務ID進行比較,假設當前讀的事務ID為read_id,記錄當前儲存的事務ID為tid,當前系統中未提交的事務中
(Read_View中)的最大最小事務ID分別為max_tid和min_tid,那麼資料可見性判斷流程為:
透過上圖(這個圖是透過分析網上的一些部落格內容得到的,和實際MySQL的邏輯細節可能不一致),在來分析上文提到的Case,由於事務B的事務ID不滿足read_id=tid||tid<min_tid的條件,
且該記錄當前有DATA_ROLL_PTR,所以最後該事務B實際讀取的是Undo Log中的記錄:
Primary Key Time Name DATA_TRX_ID DATA_ROLL_PTR
1 2018-4-28 Huan 1 NULL
需要注意的是,MySQL的MVCC和理論上的MVCC實際有所差異,MySQL同一時刻只允許一個事務去操作某條資料,該條資料上的操作實際是序列的,也就是說一條記錄的有用版本實際就只會有當前記錄
和一條Undo Log記錄,是悲觀鎖的操作方式,而MVCC的定義上實際是樂觀鎖的操作方式,某一時刻記錄可以存在很多個版本。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/15498/viewspace-2647878/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- mysql MVCC 介紹MySqlMVC
- MySQL多版本併發控制MVCC的實現示例程式碼介紹MySqlMVC
- [Mysql]MVCCMySqlMVC
- MySql介紹MySql
- MySQL(六):MySQL之MVCCMySqlMVC
- MySQL索引介紹MySql索引
- MySQL MHA介紹MySql
- Mysql MVCC機制MySqlMVC
- LAMP架構介紹、MYSQL介紹、安裝LAMP架構MySql
- LAMP架構(LAMP介紹,mysql/mariaDB介紹,Mysql安裝)LAMP架構MySql
- MySQL檢視介紹MySql
- MySQL 安裝介紹MySql
- MySQL Binlog 介紹MySql
- MySQL分支版本介紹MySql
- MySQL group replication介紹MySql
- 【MySQL】mydumper工具介紹MySql
- 【Mysql】index extensions介紹MySqlIndex
- MySQL分割槽介紹MySql
- MySQL SQL模式介紹MySql模式
- MySQL 5.5 mysqlimport介紹MySqlImport
- Amoeba for MySQL 基本介紹MySql
- MySQL MVCC實現原理MySqlMVC
- MySQL 8.0 目錄介紹MySql
- MySQL 官方工具utilities介紹MySql
- MySQL角色(role)功能介紹MySql
- MySQL觸發器介紹MySql觸發器
- MySQL MRR和ICP介紹MySql
- MySQL 教程基礎介紹MySql
- MySql主從同步介紹MySql主從同步
- MySQL 5.7 NOT EXISTS用法介紹MySql
- MySQL 8.0 新增特性介紹MySql
- MySQL SHOW STATUS命令介紹MySql
- MySQL 5.5 mysqlbinlog 介紹MySql
- MySQL 5.7 Performance Schema 介紹MySqlORM
- MySQL·引擎特性·InnoDBChangeBuffer介紹MySql
- Mysql Binlog的介紹MySql
- MySQL高可用方案介紹MySql
- MySQL鎖機制與MVCCMySqlMVC