一文讀懂MVCC:數(shù)據(jù)庫中的并發(fā)讀寫利器!
大家好,我是你們的小米,一個積極活潑、喜好分享技術(shù)的小伙伴。今天,我想和大家聊一聊數(shù)據(jù)庫領(lǐng)域的一個重要話題——MVCC多版本并發(fā)控制。MVCC是MySQL和其他一些數(shù)據(jù)庫系統(tǒng)中常用的并發(fā)控制技術(shù),通過它,我們可以在高并發(fā)讀寫的場景中提高數(shù)據(jù)庫的性能。讓我們一起來深入了解吧!
什么是MVCC
MVCC全稱為Multi-Version Concurrency Control,中文翻譯為多版本并發(fā)控制。它是一種用于數(shù)據(jù)庫系統(tǒng)中處理并發(fā)讀寫操作的技術(shù)。MVCC通過為每個讀寫操作創(chuàng)建多個版本的數(shù)據(jù)來解決并發(fā)沖突,從而實(shí)現(xiàn)了讀操作與寫操作之間的并發(fā)執(zhí)行,提高了數(shù)據(jù)庫的并發(fā)性能。
什么是當(dāng)前讀
在MVCC中,當(dāng)前讀操作是指讀取最新數(shù)據(jù)版本的操作。下面是一些常見的當(dāng)前讀語句:
SELECT ... FOR UPDATE:用于讀取數(shù)據(jù)并獲取寫鎖。
SELECT ... LOCK IN SHARE MODE:用于讀取數(shù)據(jù)并獲取讀鎖。
什么是快照讀
快照讀是指讀取歷史數(shù)據(jù)版本的操作,也可以稱為非鎖定讀操作。下面是一些常見的快照讀語句:
SELECT:普通的查詢語句,用于讀取數(shù)據(jù)。
當(dāng)前讀、快照讀、MVCC之間的關(guān)系
當(dāng)前讀和快照讀是MVCC中兩種不同的讀操作方式。當(dāng)前讀獲取的是最新的數(shù)據(jù)版本,可以用于讀寫沖突的處理,而快照讀獲取的是歷史的數(shù)據(jù)版本,用于讀取一致性的數(shù)據(jù)視圖。MVCC通過管理和維護(hù)這些不同版本的數(shù)據(jù),實(shí)現(xiàn)了并發(fā)讀寫操作。
MVCC解決的問題
數(shù)據(jù)庫并發(fā)場景有三種,分別是:
讀讀沖突:多個讀操作之間不會產(chǎn)生沖突,可以并發(fā)執(zhí)行。
讀寫沖突:讀操作不會被寫操作所阻塞,讀操作可以讀取到之前的數(shù)據(jù)版本,保證了讀的一致性。
寫寫沖突:寫操作之間不會產(chǎn)生沖突,可以并發(fā)執(zhí)行。
MVCC是一種用來解決讀寫沖突的無所并發(fā)控制,也就是為事務(wù)分配單項(xiàng)增長的時間戳,為每個修改保存一個版本,版本與事務(wù)時間戳關(guān)聯(lián),讀操作只讀該事務(wù)開始前的數(shù)據(jù)庫的快照,所以MVCC可以為數(shù)據(jù)庫解決以下問題:
并發(fā)讀寫性能提升:在并發(fā)讀寫數(shù)據(jù)庫時,MVCC可以做到在讀操作時不用阻塞寫操作,在寫操作時不用阻塞讀操作,提高了數(shù)據(jù)庫并發(fā)讀寫的性能。
事務(wù)隔離:MVCC可以解決臟讀、幻讀、不可重復(fù)讀等事務(wù)隔離的問題,但是不能解決更新丟失問題。
MVCC實(shí)現(xiàn)原理
MVCC的實(shí)現(xiàn)原理主要依賴于記錄中的三個隱藏字段、undolog、read view來實(shí)現(xiàn)的。
隱藏字段
MVCC通過在數(shù)據(jù)表中添加一些隱藏字段來實(shí)現(xiàn)多版本控制。這些隱藏字段包括:
DB_TRX_ID:用于標(biāo)識事務(wù)的唯一ID。
DB_ROLL_PTR:指向undo log中的回滾段指針。
DB_ROW_ID:用于唯一標(biāo)識一行數(shù)據(jù)。
undolog
undolog是MVCC實(shí)現(xiàn)中的一個重要組件,用于記錄數(shù)據(jù)的修改歷史。在MVCC中,insert操作和update/delete操作都會產(chǎn)生對應(yīng)的undolog。
insert操作:在插入一行數(shù)據(jù)時,會生成一條insert類型的undolog,記錄了插入數(shù)據(jù)的操作。
update和delete操作:在更新或刪除一行數(shù)據(jù)時,會生成一條delete類型的undolog,記錄了刪除或修改之前的數(shù)據(jù)。
read view
read view是MVCC中用于管理數(shù)據(jù)版本的重要概念,它是一個邏輯數(shù)據(jù)視圖。下面是一些關(guān)于read view的重要信息:
Read View的定義:Read view是一個事務(wù)開始時創(chuàng)建的數(shù)據(jù)視圖,用于確定事務(wù)的隔離級別和可見性規(guī)則。
Read View的作用:Read view用于確定一個事務(wù)可以看到哪些數(shù)據(jù)版本,以及其他事務(wù)是否可以看到該事務(wù)修改的數(shù)據(jù)。
Read View中三個全局屬性
在MVCC中,Read view具有三個全局屬性,分別是trx_list、up_limit_id和low_limit_id。
trx_list:記錄了當(dāng)前活動的事務(wù)列表,其中每個事務(wù)包含一個事務(wù)ID和一個讀視圖。
up_limit_id:是一個全局的遞增ID,用于判斷事務(wù)的可見性。
low_limit_id:是一個全局的遞增ID,用于判斷事務(wù)的可見性。
Read View的可見性比較規(guī)則
基于上述三個全局屬性,Read View的可見性比較規(guī)則如下:
如果DB_TRX_ID < up_limit_id,則當(dāng)前事務(wù)能看到DB_TRX_ID 所在的記錄,如果大于等于進(jìn)入下一個判斷;
如果 DB_TRX_ID ≥ up_limit_id,則代表 DB_TRX_ID 所在的記錄在 Read View 生成后才出現(xiàn)的,那么對于當(dāng)前事務(wù)肯定不可見,如果小于,則進(jìn)入下一步判斷;
判斷 DB_TRX_ID 是否在活躍事務(wù)中,如果在,則代表在Read View 生成時刻,這個事務(wù)還是活躍狀態(tài),還沒有 commit,修改的數(shù)據(jù),當(dāng)前事務(wù)也是看不到;如果不在,則說明這個事務(wù)在 Read View 生成之前就已經(jīng)開始 commit,那么修改的結(jié)果是能夠看見的。
MVCC的整體處理流程
假設(shè)有四個事務(wù)T1、T2、T3和T4,它們按順序開始執(zhí)行,并進(jìn)行讀寫操作。MVCC的整體處理流程如下:
T1開始執(zhí)行時,創(chuàng)建一個新的read view,并設(shè)置up_limit_id和low_limit_id為無窮大。
T1執(zhí)行讀操作,獲取到數(shù)據(jù)庫中的數(shù)據(jù)版本。
T1執(zhí)行寫操作,修改數(shù)據(jù)庫中的數(shù)據(jù),并生成對應(yīng)的undolog。
T1提交事務(wù),將up_limit_id設(shè)置為T1的事務(wù)ID。
T2開始執(zhí)行時,創(chuàng)建一個新的read view,并設(shè)置up_limit_id為無窮大,low_limit_id為T1的事務(wù)ID。
T2執(zhí)行讀操作,根據(jù)read view獲取到數(shù)據(jù)庫中的數(shù)據(jù)版本。
T3開始執(zhí)行時,創(chuàng)建一個新的read view,并設(shè)置up_limit_id為無窮大,low_limit_id為T1的事務(wù)ID。
T3執(zhí)行寫操作,修改數(shù)據(jù)庫中的數(shù)據(jù),并生成對應(yīng)的undolog。
T4開始執(zhí)行時,創(chuàng)建一個新的read view,并設(shè)置up_limit_id為無窮大,low_limit_id為T1的事務(wù)ID。
T4執(zhí)行讀操作,根據(jù)read view獲取到數(shù)據(jù)庫中的數(shù)據(jù)版本。
通過上述流程,MVCC保證了不同事務(wù)之間的并發(fā)讀寫操作,并根據(jù)每個事務(wù)的read view確定數(shù)據(jù)的可見性。
RC、RR級別下的InnoDB快照讀區(qū)別
在InnoDB中,RC(Read Committed)和RR(Repeatable Read)是兩種常見的隔離級別。在這兩種隔離級別下,InnoDB的快照讀有以下不同之處:
在RR級別下,每個事務(wù)的read view是在事務(wù)開始時創(chuàng)建的,并在整個事務(wù)期間保持不變。這意味著在RR級別下,事務(wù)可以看到之前讀取的數(shù)據(jù)版本,即使其他事務(wù)已經(jīng)修改了數(shù)據(jù)。
在RC級別下,每個語句都會創(chuàng)建一個新的read view,并在執(zhí)行語句期間保持不變。這意味著在RC級別下,事務(wù)每次讀取數(shù)據(jù)都會使用新的read view,而不會看到其他事務(wù)已經(jīng)修改的數(shù)據(jù)。
RR級別下的快照讀會導(dǎo)致更多的數(shù)據(jù)版本被保留在undo log中,因?yàn)槊總€事務(wù)的read view都需要保留。而在RC級別下,每個語句的read view只需要保留一次,因此占用的存儲空間較少。
總結(jié):在RC隔離級別下,是每個快照讀都會生成并獲取最新的 Read View;而在RR隔離級別下,則是同一個事務(wù)中的第一個快照讀會創(chuàng)建 Read View,之后的快照讀獲取的都是同一個 Read View。
總結(jié)
MVCC多版本并發(fā)控制是一種提高數(shù)據(jù)庫并發(fā)性能的重要技術(shù)。通過使用當(dāng)前讀和快照讀,MVCC能夠解決讀讀、讀寫和寫寫沖突,并提高并發(fā)讀寫數(shù)據(jù)庫的性能。它還能解決事務(wù)隔離的問題,但無法解決更新丟失問題。MVCC的實(shí)現(xiàn)原理涉及隱藏字段、undolog和read view等組件,通過管理這些組件,實(shí)現(xiàn)了并發(fā)讀寫操作。在不同的隔離級別下,快照讀的行為也會有所不同。RR級別下的快照讀可以看到之前讀取的數(shù)據(jù)版本,而RC級別下的快照讀每次讀取都使用新的read view。

END
對于數(shù)據(jù)庫開發(fā)和性能優(yōu)化來說,了解和掌握MVCC技術(shù)是非常重要的。希望本篇文章能給大家?guī)硪恍﹩l(fā)和幫助。如果有任何問題或者想法,歡迎留言討論!

