【MySQL】MVCC詳解與MVCC實(shí)現(xiàn)原理

一、什么是MVCC

MVCC,全稱 Multi-Version Concurrency Control ,MVCC是多版本并發(fā)控制的全稱,是指多版本的并發(fā)控制。MVCC是一種并發(fā)控制方法。通常,在數(shù)據(jù)庫(kù)管理系統(tǒng)中,它用編程語言實(shí)現(xiàn)對(duì)數(shù)據(jù)庫(kù)和事務(wù)存儲(chǔ)器的并發(fā)訪問。

MVCC 是一種在讀取數(shù)據(jù)時(shí)無需鎖定(加鎖)即可提高讀取效率和并發(fā)性的方法。

數(shù)據(jù)庫(kù)并發(fā)有以下情況:

1、讀-讀:沒有問題。

2、讀-寫:存在線程安全問題,這可能導(dǎo)致臟讀、幻讀和不可重復(fù)讀。

3、寫-寫:存在線程安全問題,更新可能會(huì)丟失。

二、MVCC的實(shí)現(xiàn)原理

這里面講解了,事務(wù)的特性、事務(wù)的隔離級(jí)別,當(dāng)時(shí)說MySQL事務(wù)實(shí)現(xiàn)原理有單版本控制——鎖,以及多版本控制MVCC。

現(xiàn)在我們需要知道,在讀已提交RC,Read Committed)和可重復(fù)讀RR,Repeatable Read)隔離級(jí)別下的快照讀,都是基于MVCC實(shí)現(xiàn)的!

MVCC最大的優(yōu)點(diǎn)是沒有讀鎖,讀寫之間沒有沖突。在讀多寫少的OLTP(On-Line Transaction Processing,聯(lián)機(jī)事務(wù)處理)應(yīng)用程序中,讀寫之間沒有沖突非常重要,這大大提高了系統(tǒng)的并發(fā)性。

1、MVCC多版本實(shí)現(xiàn)

為了讓您更直觀地理解MVCC的實(shí)現(xiàn)原理,這里通過事務(wù)更新一行記錄的過程的例子,來解釋MVCC中多個(gè)版本的實(shí)現(xiàn)。

假設(shè) ID~……是表中字段的名稱(DATA)。最后三個(gè)隱藏字段對(duì)應(yīng)對(duì)應(yīng)行的隱藏ID、事務(wù)編號(hào)和回滾指針,如下圖所示:

隱含ID(DB_ROW_ID),6字節(jié),當(dāng)InnoDB自動(dòng)生成聚集索引時(shí),聚集索引包括這個(gè)DB_ROW_ ID的值。

事務(wù)編號(hào)(DB_TRX_ID),6字節(jié),它標(biāo)記了此行最新更新記錄的事務(wù)ID。每個(gè)事務(wù)都被處理,其值自動(dòng)為+1。

回滾指針(DB_ROLL_PT),7個(gè)字節(jié),指向當(dāng)前記錄項(xiàng)的回滾段的撤消日志記錄,通過該記錄可以找到以前版本的數(shù)據(jù)。

具體更新過程簡(jiǎn)述如下:

首先,如果數(shù)據(jù)只是INSERT,則可以認(rèn)為ID是 1,其他兩個(gè)字段為空。

當(dāng) 事務(wù)1 更改此行的數(shù)據(jù)值時(shí),將執(zhí)行,一、使用獨(dú)占鎖鎖定行,記錄重做日志;二、將修改前這一行的值復(fù)制到Undo日志;三、修改當(dāng)前行的值,填寫事務(wù)ID,并使回滾指針指向撤銷日志中修改前的行。

接下來,與 事務(wù)1 相同。此時(shí),undo 日志中有兩行記錄,它們由回滾指針連接。

因此,如果撤消日志沒有一直被刪除,那么當(dāng)前記錄的回滾指針將追溯到創(chuàng)建該行時(shí)的初始內(nèi)容。InnoDB中有一個(gè)清除線程,將查詢比最舊的活動(dòng)事務(wù)更早的撤消日志并將其刪除,從而確保撤消日志文件不會(huì)無限增長(zhǎng)。

2、MVCC 實(shí)現(xiàn)原理

它的實(shí)現(xiàn)原理主要是依賴記錄中的 3個(gè)隱式字段(DB_ROW_ID、DB_TRX_ID、DB_ROLL_PT),undo日志 , Read View 來實(shí)現(xiàn)的。

上面我們已經(jīng)詳細(xì)介紹了3個(gè)隱式字段的含義,總結(jié)一下

默認(rèn)情況下,DB_ROW_ID 是數(shù)據(jù)庫(kù)為這行記錄生成的唯一隱式主鍵。DB_TRX_ID 是當(dāng)前操作記錄的事務(wù)ID,而 DB_ROLL_PTR 是一個(gè)回滾指針,與撤消日志一起使用以指向以前的舊版本。

有兩種 undo 日志:insert undo log、update undo log,幫助MVCC的撤銷的本質(zhì)是update undo log 。事實(shí)上,撤消日志是回滾段中的舊記錄鏈。(MySQL日志系統(tǒng)的詳解:(待補(bǔ)充))。

3、什么是 Read View

什么是 Read View ?

Read View 是事務(wù)執(zhí)行快照讀取操作時(shí)生成的視圖。在事務(wù)執(zhí)行快照讀取時(shí),將生成數(shù)據(jù)庫(kù)系統(tǒng)的當(dāng)前快照,并記錄和維護(hù)系統(tǒng)當(dāng)前活動(dòng)事務(wù)的ID(當(dāng)每個(gè)事務(wù)啟動(dòng)時(shí),將分配一個(gè)ID,該ID是增量的,因此最新事務(wù)的ID值更大)。

當(dāng)我們使用select讀取數(shù)據(jù)時(shí),此時(shí)會(huì)有許多版本的數(shù)據(jù),但我們不知道要讀取哪個(gè)版本。

此時(shí),我們依賴readview來限制我們可以讀取的版本。只有通過readview才能知道我們可以閱讀哪個(gè)版本。

3.1、Read View 解析

Read View主要用于進(jìn)行可見性判斷,也就是說,當(dāng)我們?yōu)槭聞?wù)執(zhí)行快照讀時(shí),我們會(huì)為記錄創(chuàng)建一個(gè)讀取視圖 Read View。以判斷當(dāng)前事務(wù)可以看到哪個(gè)版本的數(shù)據(jù)。它可能是當(dāng)前期間的最新數(shù)據(jù),也可能是記錄 undo log 中某個(gè)版本的數(shù)據(jù)。

讀取視圖遵循可見性算法,主要是要修改的數(shù)據(jù)的最新記錄中的 DB_TRX_ID (即當(dāng)前事務(wù)ID),并與系統(tǒng)中其他活動(dòng)事務(wù)的ID(由讀取視圖 Read View 維護(hù))進(jìn)行比較。

如果 DB_TRX_ID 跟 Read View 屬性不符合可見性,通過 DB_ROLL_PTR 回滾指針在撤消日志Undo Log中的 DB_TRX_ID 比較中檢索數(shù)據(jù)庫(kù)(遍歷鏈表的 DB_TRX_ID)。

遍歷鏈接列表的DB _ TRX_ ID(從鏈的開始到鏈的結(jié)束,即從最近的修改),直到找到滿足特定條件的 DB_TRX_ID , 那么這個(gè) DB_TRX_ID 所在的舊記錄就是當(dāng)前事務(wù)能看見的最新老版本。

3.2、Read View 含義

在一個(gè) Read View 快照中主要包括以下這些字段:

m_ids,表示生成 Read View 時(shí)當(dāng)前系統(tǒng)中活動(dòng)讀/寫事務(wù)的事務(wù)ID列表

min_trx_id,表示生成 Read View 時(shí)當(dāng)前系統(tǒng)中活動(dòng)讀/寫事務(wù)中最小的事務(wù)ID,即 m_ids 最小值

max_trx_id,表示生成 Read View 時(shí)應(yīng)分配給系統(tǒng)中下一個(gè)事務(wù)的ID值

creator_trx_id,表示生成 Read View 的事務(wù)的事務(wù)ID

3.3、Read View 如何判斷版本鏈可用

trx_id == creator_trx_id,可以訪問這個(gè)版本;

trx_id < min_trx_id,可以訪問這個(gè)版本;trx_id > max_trx_id,不可以訪問這個(gè)版本;

min_trx_id <= trx_id <= max_trx_id,如果 trx_id 在 m_ids 中不可以訪問,反之可以

三、當(dāng)前讀,快照讀與MVCC

1、什么是當(dāng)前讀和快照讀

1.1、當(dāng)前讀

select lock in share mode (共享鎖), select for update; update; insert; delete (排他鎖)這些操作都是一種當(dāng)前讀。

它讀取最新版本的記錄,讀取時(shí),它還確保其他并發(fā)事務(wù)無法修改當(dāng)前記錄,并鎖定讀取的記錄。

1.2、快照讀

不加鎖的 select 操作就是快照讀,即無鎖的非阻塞讀??;

快照讀的前提是隔離級(jí)別不是串行級(jí)別,在串行級(jí)別下讀取的快照將退化為當(dāng)前讀取,發(fā)生快照讀的原因是基于提高并發(fā)性能的考慮。

快照讀的實(shí)現(xiàn)基于多版本并發(fā)控制,即MVCC。MVCC可以被認(rèn)為是行鎖的變體,但在許多情況下,它避免了鎖操作并減少了開銷;由于它基于多個(gè)版本,也就是說,讀取的快照可能不是數(shù)據(jù)的最新版本,而是以前的歷史版本

MVCC的設(shè)計(jì)目的是在不鎖定讀寫沖突,這種讀取指的是快照讀取,而不是當(dāng)前讀取。

當(dāng)前的讀取實(shí)際上是一個(gè)鎖操作,這是悲觀鎖的實(shí)現(xiàn)

2、快照讀、當(dāng)前讀與MVCC辨析

MVCC多版本并發(fā)控制的概念是“維護(hù)一個(gè)數(shù)據(jù)的多個(gè)版本,以便讀寫操作之間沒有沖突”。

因?yàn)镸VCC只是一個(gè)抽象的概念,為了實(shí)現(xiàn)這樣的概念,MySQL需要提供特定的功能來實(shí)現(xiàn)它?!翱煺兆x取是MySQL MVCC理想模型的非阻塞讀取功能之一”。

相對(duì)而言,當(dāng)前讀是悲觀鎖的具體功能實(shí)現(xiàn),快照閱讀本身也是一個(gè)抽象概念。

3、MVCC 只在 RC 和 RR 隔離級(jí)別下工作

一、 在RC(Read Commited )的隔離級(jí)別下,每次快照讀取都會(huì)生成并獲得最新的 readview。

二、在RR(Repeatable Read)隔離級(jí)別,只有讀取同一事務(wù)的第一個(gè)快照才能創(chuàng)建 readview。每個(gè)后續(xù)快照讀取都使用相同的 readview,因此每個(gè)查詢結(jié)果都相同。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容