目錄概述
mysql innodb下讀操作分類
一、快照讀(snapshot read)
二、當前讀(current read)
三、當前讀,快照讀和mvcc的關係
mysql mvcc實現原理
一、innodb引擎的隱式字段
二、undo日誌版本鏈
三、read view
四、可見性比較演算法 結論
mvcc(multi-version concurrency control 多版本併發控制),是一種不利用鎖機制實現的隔離級別,主要實現了在保證資料的一致性的前提下,實現了讀寫的並行。從而大大提高資料庫系統的併發效能。
資料庫併發場景有三種,分別為:
引入了mvcc技術可以為資料庫解決以下問題
這樣大幅度提高了併發度。這也是為什麼現階段,幾乎所有的rdbms(關係型資料庫管理系統),都支援了mvcc。
了解mvcc技術前,我們先了解下mysql innodb的讀操作是如何的?
在mvcc併發控制中,讀操作可以分成兩類:快照讀 (snapshot read)與當前讀 (current read)。快照讀,讀取的是記錄的可見版本 (有可能是歷史版本),不用加鎖。而當前讀,讀取的是記錄的最新版本,並且,當前讀返回的記錄,都會加上鎖,保證其他事務不會再併發修改這條記錄。
讀取的是記錄的可見版本 (有可能是歷史版本),不用加鎖。
簡單的select操作,屬於快照讀,不加鎖:
select * from table where ***x;
當執行select之後innodb缺省會執行快照讀,相當於就是給你目前的狀態找了一張**,以後執行select 的時候就會返回當前**裡面的資料,當其他事務提交了也對你不造成影響,和你沒關係,這就實現了可重複讀了,那這個**是什麼時候生成的呢?不是開啟事務的時候,是當你第一次執行select的時候,也就是說,當a開啟了事務,然後沒有執行任何操作,這時候b insert了一條資料然後commit,這時候a執行 select,那麼返回的資料中就會有b新增的那條資料......之後無論再有其他事務commit都沒有關係,因為**已經生成了,而且不會再生成了,以後都會參考這張**。
當前讀,讀取的是記錄的最新版本,並且,當前讀返回的記錄,都會加上鎖,保證其他事務不會再併發修改這條記錄。
特殊的讀操作,插入/更新/刪除操作,屬於當前讀,需要加鎖。
當執行上述幾個操作的時候缺省會執行當前讀,也就是會讀取最新的記錄,也就是別的事務提交的資料你也可以看到,這樣很好理解啊,假設你要update乙個記錄,另乙個事務已經delete這條資料並且commit了,這樣不是會產生衝突嗎,所以你update的時候肯定要知道最新的資訊啊。select * from table where *** lock in share mode;
select * from table where *** for update;
insert into table values (…);
update table set *** where ***;
delete from table where ***;
innodb會為資料預設建立三個隱式字段,db_row_id、db_trx_id、db_roll_ptr。含義如下所示:
如上圖,db_row_id是資料庫預設為該行記錄生成的唯一隱式主鍵,db_trx_id是當前操作該記錄的事務id,而db_roll_ptr是乙個回滾指標,用於配合undo日誌,指向上乙個舊版本。
最後我們來舉個例子讓我們更好理解上面的內容。
比如我們有如下表:
mysql底層實際儲存格式如下
比如現在有個事務id是11的執行的這條記錄的修改語句
update mvcc_test set salary = 200 where id = 1
底層資料格式變化如下
比如現在有個事務id是12的執行的這條記錄的修改語句
update mvcc_test set salary = 300 where id = 1
底層資料格式變化如下
readview說白了就是乙個資料結構,在sql開始的時候被建立。這個資料結構中包含了3個主要的成員:readview,在併發情況下,乙個事務在啟動時,trx_sys鍊錶中存在部分還未提交的事務,那麼哪些改變對當前事務是可見的,哪些又是不可見的,這個需要通過readview來進行判定,首先來看下readview中的3個成員各自代表的意思。
前面提到了事務是如何實現隔離,就是通過這個可見性比較演算法來進行事務隔離的,讓當前事務只能讀到當前事務沿著undo log鏈應該讀到的資料。
在這裡記錄下rr級別下的比較演算法,其實rc級別下的比較演算法和它是一樣的,我們暫且描述一次:
首先,我們會有乙個trx_id_current表示該行最穩定的事務id。
當我們開啟乙個新事務去讀取改行記錄的時候,innodb會建立乙個read view(快照),它維護了當前活躍的事務id(也就是未提交的事務),我們姑且稱那個最早的事務id為up_trx_id,最晚的事務id為low_trx_id。
接下來我們會根據這幾個值進行描述比較演算法:
當trx_id_current < up_trx_id的時候,說明該行資料的穩定事務id小於活躍事務id的,所以該行資料是可見的,跳到步驟五
當trx_id_current > low_trx_id的時候,說明該行資料的穩定事務id大於當前快照下的活躍事務id,所以說該行資料是不可見的,跳到步驟四。
當up_trx_id < trx_id_current < low_trx_id,在這個範圍的事務id,那就在read view裡的活躍事務id中遍歷,如果trx_id_current == 其中乙個事務id,那麼就說明改行資料不可見。跳到步驟四。否則表示可見。
從該行記錄的回滾指標(db_roll_pir)指向的下乙個最新的事務id,將這個值賦值給trx_id_current,繼續從步驟1開始。
將該可見行的資料返回。
用一張圖來解釋mysql中的mvcc實現如下所示:
資料庫需要做好版本控制,防止不該被事務看到的資料(例如還沒提交的事務修改的資料)被看到。在innodb中,mvcc技術主要是通過使用readview的技術來實現判斷。查詢出來的每一行記錄,都會用readview來判斷一下當前這行是否可以被當前事務看到,如果可以,則輸出,否則就利用undolog來構建歷史版本,再進行判斷,知道記錄構建到最老的版本或者可見性條件滿足。
mvcc的優點是在大多數情況下代替了行鎖,實現了對讀的非阻塞,讀不加鎖,讀寫不衝突。
mvcc的缺點是每行記錄都需要額外的儲存空間,需要做更多的行維護和檢查工作。
mvcc機制極大的提高了資料庫的併發處理能力,所以目前主流的資料庫都有通過不同的手段來實現這一機制來提公升效能。
參考資料
資料庫事務簡介
在資料庫系統中,事務是工作的離散單位,它可以是修改乙個使用者的賬戶餘額,也可以是庫存項的寫操作。在單使用者 單資料庫環境下執行事務比較簡單,但在分布式環境下,維護多個資料庫的完整性就比較複雜。大多數聯機事務處理系統是在大型計算機上實現的,這是由於它的操作複雜,需要快速的輸入 輸出和完善的管理。如果乙...
為 Key Value 資料庫實現MVCC 事務
acid是軟體領域使用最廣泛的技術之一,它是關聯式資料庫的基石,是企業級中介軟體不可或缺的部分,但通常通過黑盒的方式提供。但是在許多情況下,這種古老的事務方式已經不能夠適應現代大規模系統和nosql資料庫的需要了,現代系統要求更高的效能要求,更大的資料量,更高的可用性。在這種情況下,傳統的事務模型被...
資料庫事務隔離級別與MVCC
事務隔離級別包括 讀未提交 read uncommitted 讀提交 read committed 可重複讀 repeatable read 和序列化 serializable 在實現上,資料庫裡面會建立乙個檢視,訪問的時候以檢視的邏輯結果為準。在可重複讀隔離級別下,這個檢視是在事務啟動時建立的,整...