石家莊造價工程信息網(wǎng)杭州新站整站seo
MVCC到底是什么
????????MVCC(Multi-Version Concurrency Control)是一種并發(fā)控制機制,用于解決并發(fā)訪問數(shù)據(jù)庫時的數(shù)據(jù)一致性和隔離性問題。MVCC允許多個事務同時讀取數(shù)據(jù)庫的同一數(shù)據(jù),而不會相互干擾或導致沖突。
????????在傳統(tǒng)的并發(fā)控制機制中,如鎖定機制,事務會對讀取和寫入的數(shù)據(jù)進行加鎖,以確保每個事務獨占所需的資源。然而,這種悲觀并發(fā)控制機制可能導致資源爭用和性能問題,尤其是在高并發(fā)環(huán)境下。
?MVCC是innodb實現(xiàn)事務并發(fā)與回滾的重要功能!!!!!
MVCC解決了哪些問題
MVCC(Multi-Version Concurrency Control)解決了以下幾個關鍵問題:
-
讀-寫沖突:傳統(tǒng)的并發(fā)控制機制,如鎖定機制,可能導致讀取和寫入操作之間的沖突。當多個事務試圖同時讀取和寫入相同的數(shù)據(jù)時,會發(fā)生資源爭用問題。MVCC通過并發(fā)控制的方式,讓讀取操作不受寫入操作的干擾,從而避免了這種讀-寫沖突。
-
寫-寫沖突:在傳統(tǒng)的并發(fā)控制機制中,當多個事務同時試圖寫入相同的數(shù)據(jù)時,會發(fā)生寫入沖突。這可能導致數(shù)據(jù)的不一致性以及事務的回滾和重試。MVCC通過并發(fā)控制,使得每個事務都操作自己的獨立版本,從而避免了寫-寫沖突,提高了并發(fā)性能。
-
隔離性問題:在多用戶并發(fā)操作中,隔離性是確保事務之間互不干擾的重要屬性。傳統(tǒng)的并發(fā)控制機制,如鎖定機制,可能導致事務之間的阻塞和相互等待。MVCC通過使用多個版本和快照讀取,實現(xiàn)了事務之間的隔離性,使得事務可以并發(fā)執(zhí)行而互不干擾。
-
性能問題:傳統(tǒng)的并發(fā)控制機制中,加鎖的方式可能導致較高的開銷和資源爭用,特別是在高并發(fā)環(huán)境下。MVCC采用了樂觀的并發(fā)控制方式,減少了鎖沖突和資源爭用,從而提高了并發(fā)性能和系統(tǒng)吞吐量。
綜上所述,MVCC通過解決讀-寫沖突、寫-寫沖突、隔離性問題和性能問題,提供了更好的并發(fā)控制機制。它通過版本管理和快照讀取,使得多個事務可以并發(fā)執(zhí)行而互不干擾,從而提高了數(shù)據(jù)庫的性能、可用性和一致性。
MVCC底層機制-具體實現(xiàn)
具體的實現(xiàn)是,在數(shù)據(jù)庫的每一行中,添加額外的三個字段:
- DB_TRX_ID – 記錄插入或更新該行的最后一個事務的事務 ID
- DB_ROLL_PTR – 指向改行對應的 undolog 的指針
- DB_ROW_ID – 單調(diào)遞增的行 ID,他就是 AUTO_INCREMENT 的主鍵 ID
在MVCC的實現(xiàn)中,使用樂觀鎖和額外的字段來實現(xiàn)并發(fā)控制。以下是對每個字段的具體解釋和MVCC如何使用樂觀鎖的簡單概述:
-
DB_TRX_ID(事務ID):這個字段用于記錄插入或更新行的最后一個事務的事務ID。每個事務在執(zhí)行寫操作時,都會生成一個唯一的事務ID并關聯(lián)到相關數(shù)據(jù)行。這樣,MVCC可以通過比較事務ID來確定事務執(zhí)行期間的數(shù)據(jù)版本。
-
DB_ROLL_PTR(undolog指針):這個字段指向對應行的undolog的指針。undolog是InnoDB存儲引擎用于實現(xiàn)事務的撤銷(undo)或回滾(rollback)操作的日志。通過保留undolog指針,MVCC可以在事務回滾或讀取舊版本數(shù)據(jù)時進行快速回溯到適當?shù)膗ndolog。
-
DB_ROW_ID(行ID):這個字段是單調(diào)遞增的行ID,通常用作AUTO_INCREMENT主鍵ID。它提供了一種方式來唯一標識每一行,以便MVCC在處理并發(fā)操作時進行準確定位。
MVCC使用樂觀鎖來確保對數(shù)據(jù)行的并發(fā)訪問不會產(chǎn)生沖突。它通過比較事務的啟動時間戳(或序列號)和數(shù)據(jù)行的事務ID來判斷是否存在并發(fā)沖突。當一個事務啟動時,會獲取所有需要讀取或修改的數(shù)據(jù)行的版本信息,包括DB_TRX_ID和DB_ROLL_PTR字段。在讀取或修改數(shù)據(jù)時,MVCC會使用這些版本信息進行驗證,以確定是否訪問的是合適的數(shù)據(jù)版本。
如果在事務執(zhí)行期間,發(fā)現(xiàn)其他事務已經(jīng)修改了數(shù)據(jù)行的版本(事務ID不一致),則會回滾當前事務,因為它訪問的是過期的數(shù)據(jù)版本。這種方式可以避免讀-寫沖突和寫-寫沖突,提供了一致的數(shù)據(jù)訪問和更新。
需要注意的是,MVCC的具體實現(xiàn)可能會有一些細微的差異,因為不同的數(shù)據(jù)庫管理系統(tǒng)可能采用不同的方式來處理并發(fā)控制。但是上述提到的字段和基本思想是MVCC的常見實現(xiàn)方式之一。
總而言之,MVCC使用樂觀鎖和額外的字段來實現(xiàn)并發(fā)控制。通過比較事務ID和版本信息,MVCC可以識別并處理并發(fā)訪問沖突,從而確保數(shù)據(jù)的一致性和隔離性。
悲觀鎖和樂觀鎖的對比
Mysql--技術文檔--悲觀鎖、樂觀鎖-《控制并發(fā)機制簡單認知、深度理解》_一單成的博客-CSDN博客
MVCC實現(xiàn)的三大要素
使用范圍:
? ? ? ? 首先要明白mvcc只在REPEATABLE READ(可重復讀) 和 READ COMMITTED(已讀提交)這兩個隔離級別下面使用。
REPEATABLE(可重復的)、COMMITTED(承諾)
MVCC實現(xiàn)原理是兩個隱式字段、undo日志、Read view來實現(xiàn)的。
1. 隱式字段
在Innodb存儲引擎中,在有聚簇索引的情況下每一行記錄中都會隱藏倆個字段,如果沒有聚簇索引則還有一個6byte的隱藏主鍵。
這倆個隱藏列一個記錄的是何時被創(chuàng)建的,一個記錄的是什么時候被刪除。
這里不要理解為是記錄的是時間,存儲的是事務ID。
倆個隱式字段為DB_TRX_ID,DB_ROLL_PTR,沒有聚簇索引還會有DB_ROW_ID這個字段。
- DB_TRX_ID:記錄創(chuàng)建這條數(shù)據(jù)上次修改它的事務 ID
- DB_ROLL_PTR:回滾指針,指向這條記錄的上一個版本
????????隱式字段實際還有一個delete flag字段,即記錄被更新或刪除,這里的刪除并不代表真的刪除,而是將這條記錄的delete flag改為true
????????MySQL提供了邏輯刪除的方式,可以通過在表中添加一個額外的列(例如delete_flag字段)來實現(xiàn)。邏輯刪除是將記錄標記為已刪除的狀態(tài),而不是將其物理刪除。這種方式保留了記錄的歷史信息,并且可以根據(jù)需要恢復或審計已刪除的記錄。在執(zhí)行查詢操作時,可以使用查詢條件來過濾掉已標記為刪除的記錄。
2. undo log(回滾日志)
之前對undo log的作用只提到了回滾操作實現(xiàn)原子性,現(xiàn)在需要知道的另一個作用就是實現(xiàn)MVCC多版本控制器。
undo log細分為倆種,insert時產(chǎn)生的undo log、update,delete時產(chǎn)生的undo log
在Innodb中insert產(chǎn)生的undo log在提交事務之后就會被刪除,因為新插入的數(shù)據(jù)沒有歷史版本,所以無需維護undo log。
update和delete操作產(chǎn)生的undo log都屬于一種類型,在事務回滾時需要,而且在快照讀時也需要,則需要維護多個版本信息。只有在快照讀和事務回滾不涉及該日志時,對應的日志才會被purge
線程統(tǒng)一刪除。
purge線程會清理undo log的歷史版本,同樣也會清理del flag標記的記錄。
undo log在mvcc中的作用
寫到這里關于undo log在mvcc中的作用估計還是蒙圈的。
undo log保存的是一個版本鏈,也就是使用DB_ROLL_PTR這個字段來連接的。
當數(shù)據(jù)庫執(zhí)行一個select語句時會產(chǎn)生一致性視圖read view
。
那么這個read view是由查詢時所有未提交事務ID組成的數(shù)組,數(shù)組中最小的事務ID為min_id和已創(chuàng)建的最大事務ID為max_id組成,查詢的數(shù)據(jù)結果需要跟read-view做比較從而得到快照結果。
所以說undo log在mvcc中的作用就是為了根據(jù)存儲的事務ID和一致性視圖做對比,從而得到快照結果。
3、undo log底層實現(xiàn)
在原始數(shù)據(jù)執(zhí)行一條語句之后將undo log記錄發(fā)生變化。
也就是說在一條語句更新的時候會把原有的數(shù)據(jù)拷貝到undo log日志中。
然后使用指針在最新的記錄和舊的記錄連接一條線,也就是存放undo log日志的指針地址。
最后需要的時候通過指針來找到歷史數(shù)據(jù)。
Undo Log(回滾日志)是用于實現(xiàn)事務的原子性和一致性的一個重要組成部分。它是在事務執(zhí)行期間記錄數(shù)據(jù)修改操作的地方,并可用于回滾事務或恢復數(shù)據(jù)到之前的狀態(tài)。
Undo Log的底層實現(xiàn)是通過使用一種稱為"回滾段"的數(shù)據(jù)結構?;貪L段是專門用于存儲Undo Log的數(shù)據(jù)結構,它位于表空間中的一個特殊位置。
每個事務在執(zhí)行修改操作前,會在Undo Log中為所涉及的數(shù)據(jù)行生成一個“回滾記錄”。這個回滾記錄存儲了修改前的數(shù)據(jù)值(原始數(shù)據(jù)值),以及用于回滾操作的其他相關信息。
當事務需要回滾時,Undo Log可以通過相反的操作撤消該事務的修改。它會使用回滾記錄中的原始數(shù)據(jù)值來將數(shù)據(jù)恢復到事務開始之前的狀態(tài)。
此外,Undo Log還用于處理并發(fā)事務之間的讀取一致性。在MVCC中,讀取操作需要使用Undo Log來判斷某個數(shù)據(jù)版本是否對當前事務可見。
總的來說,Undo Log的底層實現(xiàn)基于回滾段數(shù)據(jù)結構,它在事務執(zhí)行期間記錄數(shù)據(jù)的修改操作,并在事務回滾或 MVCC 快照讀取時使用這些信息。這個機制確保了事務的原子性、一致性和隔離性,并為數(shù)據(jù)庫提供了數(shù)據(jù)恢復和讀取一致性的支持。
4、read-view
MySQL中的read-view(讀視圖)。在MySQL中,視圖是一種虛擬表,它是根據(jù)一個或多個表的查詢結果創(chuàng)建的。視圖可以被看作是存儲在數(shù)據(jù)庫中的虛擬表格,可以像表一樣查詢和使用。
使用read-view可以實現(xiàn)以下功能:
-
簡化復雜的查詢:通過創(chuàng)建視圖,你可以將復雜的查詢邏輯封裝到一個簡單的視圖中,然后在查詢中使用該視圖,從而簡化查詢語句。
-
訪問權限控制:通過使用視圖,你可以只向用戶展示需要的數(shù)據(jù),而隱藏底層表的細節(jié)。這提供了更好的安全性和數(shù)據(jù)訪問控制。
-
數(shù)據(jù)的邏輯組織:通過創(chuàng)建視圖,你可以根據(jù)業(yè)務需求將表的數(shù)據(jù)進行組織和過濾,從而更好地管理和理解數(shù)據(jù)。
總之,read-view(讀視圖)是在MySQL中創(chuàng)建的一種虛擬表,可以用于簡化查詢、控制數(shù)據(jù)訪問權限以及邏輯組織數(shù)據(jù)。
當執(zhí)行SQL語句查詢時會產(chǎn)生一致性視圖,也就是read-view,它是由查詢的那一時間所有未提交事務ID組成的數(shù)組,和已經(jīng)創(chuàng)建的最大事務ID組成的。
在這個數(shù)組中最小的事務ID被稱之為min_id,最大事務ID被稱之為max_id,查詢的數(shù)據(jù)結果要根據(jù)read-view做對比從而得到快照結果。
阿丹理解:
? ? ? ? 這個概念其實就是在mysql中mvcc中的類似于快照的概念,因為innodb不是使用的是mvcc+樂觀鎖來解決并發(fā)問題嘛,對于操作進行鎖不對讀來鎖,然后在進行操作的時候去對比之前的改之前的版本的。
? ? ? ? 這個概念對于mvcc的作用是在一個事務開始時,它會根據(jù)自己的Read-View創(chuàng)建一個快照,并在整個事務期間使用這個快照進行讀取操作。這個快照包含了事務開始時數(shù)據(jù)庫的一個一致視圖。
5、版本鏈對比規(guī)則
MVCC在MySQL中的實現(xiàn)底層包括以下幾個組成部分:
-
版本鏈:每個數(shù)據(jù)行都有一個版本鏈,用于存儲該數(shù)據(jù)行的多個版本。版本鏈可以是鏈表或者樹形結構,具體的實現(xiàn)取決于MySQL的版本和存儲引擎。版本鏈中的每個版本都包含了數(shù)據(jù)的實際內(nèi)容以及相關的時間戳信息。
-
事務的時間戳:每個事務在開始時都會被分配一個時間戳。事務的時間戳用于判斷每個版本對于該事務的可見性。
-
數(shù)據(jù)行的鎖:為了保證并發(fā)事務的一致性,MySQL使用了鎖機制。在MVCC中,數(shù)據(jù)行的讀鎖會阻止寫事務對該數(shù)據(jù)行的修改操作,而寫鎖會阻止其他事務對該數(shù)據(jù)行的讀寫操作。
-
讀取操作的一致性視圖:每個事務在執(zhí)行讀取操作時會創(chuàng)建一個一致性視圖。該一致性視圖會基于事務的時間戳和數(shù)據(jù)行版本的時間戳來確定每個數(shù)據(jù)行對于該事務的可見性。
不同的存儲引擎在MVCC的實現(xiàn)上可能會有細微的差異,因為存儲引擎負責管理數(shù)據(jù)的存儲和訪問。例如,InnoDB存儲引擎使用了undo日志和read-view機制來實現(xiàn)MVCC,而MyISAM存儲引擎則沒有內(nèi)置的MVCC實現(xiàn)。
如果落在trx_id<min_id,表示此版本是已經(jīng)提交的事務生成的,由于事務已經(jīng)提交所以數(shù)據(jù)是可見的
如果落在trx_id>max_id,表示此版本是由將來啟動的事務生成的,是肯定不可見的
若在min_id<=trx_id<=max_id時
- 如果row的trx_id在數(shù)組中,表示此版本是由還沒提交的事務生成的,不可見,但是當前自己的事務是可見的
- 如果row的trx_id不在數(shù)組中,表明是提交的事務生成了該版本,可見
在這里還有一個特殊情況那就是對于已經(jīng)刪除的數(shù)據(jù),在之前的undo log日志講述時說了update和delete是同一種類型的undo log,同樣也可以認為delete就是update的特殊情況。
當刪除一條數(shù)據(jù)時會將版本鏈上最新的數(shù)據(jù)復制一份,然后將trx_id修改為刪除時的trx_id,同時在該記錄的頭信息中存在一個delete flag標記,將這個標記寫上true,用來表示當前記錄已經(jīng)刪除。
在查詢時按照版本鏈的規(guī)則查詢到對應的記錄,如果delete flag標記位為true,意味著數(shù)據(jù)已經(jīng)被刪除,則不返回數(shù)據(jù)。
?trx_id:
代表事務ID,用于標識每個事務的唯一性。它可以用于確定事務的開始時間和提交時間。
min_id:
最小可見事務ID。它表示正在執(zhí)行的事務所能看到的最早提交的事務的ID。事務ID小于"min_id"的所有事務都是已經(jīng)提交的事務,對于當前事務而言,它們的修改是可見的。
總結:
"trx_id"和"min_id"是MVCC中用于判斷數(shù)據(jù)對于當前事務的可見性的重要標識。
注意:
對于已經(jīng)刪除的數(shù)據(jù),在MVCC中會將最新版本的數(shù)據(jù)進行復制,并將"trx_id"修改為刪除時的"trx_id"。同時,在記錄的頭信息中設置一個"delete flag"標記來表示該記錄已經(jīng)被刪除。當查詢時根據(jù)版本鏈的規(guī)則進行查詢,如果"delete flag"標記為true,表示該數(shù)據(jù)已經(jīng)被刪除,因此不返回數(shù)據(jù)。