搜尋
首頁資料庫mysql教程MySQL多版本並發控制MVCC實例分析

MySQL多版本並發控制MVCC實例分析

Jun 03, 2023 am 11:51 AM
mysqlmvcc

    1.什麼是MVCC

    MVCC (Multiversion Concurrency Control),多版本並發控制。顧名思義,MVCC是透過資料行的多個版本管理來實現資料庫的並發控制。這項技術使得在InnoDB的交易隔離等級下執行一致性讀取.操作有了保證。換言之,就是為了查詢一些正在被另一個事務更新的行,並且可以看到它們被更新之前的值,這樣在做查詢的時候就不用等待另一個事務釋放鎖定。

    MVCC沒有正式的標準,在不同的DBMS中MVCC的實作方式可能是不同的,也不是普遍使用的(大家可以參考相關的DBMS文件)。這裡講解InnoDB中MVCC的實作機制(MySQL其它的儲存引擎並不支援它)

    2快照讀取與目前讀取

    MVCC在MySQL InnoDB中的實作主要是為了提高資料庫並發效能,用更好的方式去處理讀-寫衝突,做到即使有讀寫衝突時,也能做到不加鎖非阻塞並發讀,而這個讀指的就是快照讀,而不是目前讀。目前讀取其實是一種加鎖的操作,是悲觀鎖的實現。而MVCC本質是採用樂觀鎖思想的一種方式。

    2.1 快照讀

    快照讀又叫一致性讀,讀取的是快照資料。 不加鎖的簡單的SELECT都屬於快照讀即不加鎖的非阻塞讀;比如這樣:

    select * from player where ...

    之所以出現快照讀的情況,是基於提高並發效能的考慮,快照讀取的實作是基於MVCC,它在許多情況下,避免了加鎖操作,降低了開銷。

    既然是基於多個版本,那麼快照讀取可能讀到的並不一定是資料的最新版本,而有可能是先前的歷史版本。

    快照讀取的前提是隔離級別不是串行級別,串行級別下的快照讀取會退化成當前讀取。

    2.2目前讀

    目前讀取讀取的是記錄的最新版本(最新數據,而不是歷史版本的數據),讀取時還要保證其他並發事務不能修改當前記錄,會對讀取的記錄進行加鎖。加鎖的SELECT,或資料增刪改都會進行目前讀取。 例如:

    MySQL多版本並發控制MVCC實例分析

    3.複習

    3.1 再談隔離等級

    我們知道交易有4個隔離級別,可能有三種並發問題:

    MySQL多版本並發控制MVCC實例分析

    在MysQL 中,預設的隔離等級是可重複讀,可以解決髒讀和不可重複讀的問題,如果僅從定義的角度來看,它並不能解決幻讀問題。如果我們想要解決幻讀問題,就需要採用串列化的方式,也就是將隔離等級提升到最高,但這樣一來就會大幅降低資料庫的事務並發能力。

    MVCC可以不採用鎖定機制,而是透過樂觀鎖的方式來解決不可重複讀取和幻讀問題!它可以在大多數情況下替代行級鎖,降低系統的開銷。

    MySQL多版本並發控制MVCC實例分析

    3.2 隱藏欄位、Undo Log版本鏈

    回顧undo日誌的版本鏈,對於使用InnoDB儲存引擎的表來說,它的聚簇索引記錄中都包含兩個必要的隱藏列。

    trx_id:每次一個交易對某條叢集索引記錄進行改變時,都會把該交易的交易id賦值給trx_id隱藏欄位。 roll_pointer:每次對某條聚簇索引記錄進行改動時,都會把舊的版本寫入到undo日誌中,然後這個隱藏列就相當於一個指針,可以透過它來找到該記錄修改前的信息。

    MySQL多版本並發控制MVCC實例分析

    MySQL多版本並發控制MVCC實例分析

    MySQL多版本並發控制MVCC實例分析

    MySQL多版本並發控制MVCC實例分析

    #4、MVCC實作原理之ReadView

    MVCC的實作依賴:隱藏欄位、Undo Log、Read View

    4.1什麼是ReadView

    在MVCC機制中,多個事務對同一行記錄進行更新會產生多個歷史快照,這些歷史快照保存在Undo Log裡。如果一個事務想要查詢這個行記錄,需要讀取哪個版本的行記錄呢?這時就需要用到ReadView了,它幫我們解決了行的可見性問題。

    當交易使用MVCC機制進行快照讀取操作時,會產生一個讀取視圖,而這個視圖就是ReadView。當事務啟動時,會產生資料庫系統目前的快照,InnoDB為每個事務建構了一個數組,用來記錄並維護系統當前活躍事務的lD(“"活躍"指的就是,啟動了但還沒提交)。

    4.2 設計想法

    使用READ UNCOMMITTED隔離等級的事務,由於可以讀到未提交事務修改過的記錄,所以直接讀取記錄的最新版本就好了。

    使用SERIALIZABLE隔離等級的事務,InnoDB規定使用加鎖的方式來存取記錄。

    使用READ COMMITTEDREPEATABLE READ隔離層級的事務,都必須保證讀到已經提交了的事務修改過的記錄。假如另一個事務已經修改了記錄但是尚未提交,是不能直接讀取最新版本的記錄的,核心問題就是需要判斷版本鏈中的哪個版本是當前事務可見的,這是ReadView要解決的主要問題。

    這個ReadView中主要包含4個比較重要的內容,分別如下:

    MySQL多版本並發控制MVCC實例分析

    4.3 ReadView的規則

    有了這個ReadView,這樣在存取某筆記錄時,只需要依照下邊的步驟判斷記錄的某個版本是否可見。

    • 如果被存取版本的trx_id屬性值與ReadView中的creator_trx_id#值相同,意味著目前事務在存取它自己修改過的記錄,所以該版本可以被目前事務存取。

    • #如果被存取版本的trx_id屬性值小於ReadView中的up_limit_id值,表示產生該版本的事務在目前事務產生ReadView前已經提交,所以該版本可以被目前事務存取。

    • 如果被存取版本的trx_id屬性值大於或等於ReadView中的low_limit_id值,表示產生該版本的事務在目前事務產生ReadView後才開啟,所以該版本不可以被目前事務存取。

    • 如果被存取版本的trx_id屬性值在ReadView的up_limit_idlow_limit_id之間,那就需要判斷trx_id屬性值是不是在trx_ids清單中。如果在,說明建立ReadView時產生該版本的事務還是活躍的,則該版本不可以被存取。如果不在,說明在建立ReadView時產生該版本的交易已經被提交,該版本可以被存取。 4.4 MVCC整體操作流程

    了解了這些概念之後,我們來看下當查詢一筆記錄的時候,系統如何透過MVCC找到它:

    • 1.先取得交易自己的版本號,也就是交易ID;

    • 2.取得ReadView;

    • 3.查詢所得到的數據,然後與ReadView中的事務版本號進行比較;

    • #4.如果不符合Readview規則,就需要從Undo Log取得歷史快照;

    • #5.最後傳回符合規則的資料。

    如果某個版本的數據對當前事務不可見的話,那就順著版本鏈找到下一個版本的數據,繼續按照上邊的步驟判斷可見性,依此類推,直到版本鏈中的最後一個版本。如果最近版本不可見,則該記錄對該交易不可見,且查詢結果中不包含該記錄。在

    InnoDB中,MVCC是透過Undo Log Read View進行資料讀取,Undo Log保存了歷史快照,而Read View規則幫我們判斷目前版本的資料是否可見。

    在隔離層級為讀取已提交(Read Committed)時,一個交易中的每一次select查詢都會重新取得一次Read View。

    MySQL多版本並發控制MVCC實例分析

    當隔離等級為可重讀的時候,就避免了不可重複讀,這是因為一個交易只在第一次select的時候會取得一次Read View,而後面所有的select都會重複使用這個Read View,

    如下:

    MySQL多版本並發控制MVCC實例分析

    5.舉例說明

    假設現在student表中只有一筆由交易id8交易插入一筆記錄:

    MySQL多版本並發控制MVCC實例分析

    ##MVCC只能在READ COMMITTED和REPEATABLE READ兩個隔離等級下運作。接下來看一下

    READ COMMITTEDREPEATABLE READ所謂的生成Readview的時機不同到底不同在哪裡。

    5.1 READ COMMITTED

    #隔離等級下:

    READ COMMITTED:每次讀取資料前都會產生一個ReadView

    現在有兩個交易id分別為10、20的交易在執行:

    MySQL多版本並發控制MVCC實例分析

    說明:交易執行在過程中,只有在第一次真正修改記錄時(例如使用INSERT、DELETE、UPDATE語句),才會被指派一個單獨的事務id,這個事務id是遞增的。所以我們才在事務2中更新一些別的表的記錄,目的是讓它分配事務id。

    哈哈此刻,表student中id為1的記錄所得到的版本鍊錶如下所示:

    MySQL多版本並發控制MVCC實例分析

    假設現在有一個使用READ COMMITED隔離等級的交易開始執行:

    MySQL多版本並發控制MVCC實例分析

    #這個SELECT1的執行過程如下:

    步驟1∶在執行SELECT語句時會先生成一個ReadView ,ReadView的trx_ids列表的內容就是[10,20],up_limit_id10, low_limit_id21 , creator_trx_id0
    步驟2:從版本鏈中挑選可見的記錄,從圖中看出,最新版本的列name的內容是'王五',該版本的trx_id值為10,在trx_ids清單內,所以不符合可見性要求,根據roll_pointer跳到下一個版本。
    步驟3:下一個版本的欄位name的內容是'李四',該版本的trx_id值也是10,也在trx_ids清單內,所以也不符合要求,繼續跳到下一個版本。
    步驟4:下一個版本的欄位name的內容是‘張三',該版本的trx_id值為8,小於ReadView 中的up_limit_id值10,所以這個版本是符合要求的,最後回傳給使用者的版本就是這條列name為‘張三’的記錄。

    之後,我們把交易id10的交易提交一下:

    MySQL多版本並發控制MVCC實例分析

    ##然後到

    事務id20的事務中更新一下表格studentid1的記錄:

    MySQL多版本並發控制MVCC實例分析

    此時,表student中id為1的記錄的版本鏈就長這樣:

    MySQL多版本並發控制MVCC實例分析

    然後再到剛才使用READ COMMITTED隔離等級的交易中繼續找出id為1的記錄,

    如下:

    MySQL多版本並發控制MVCC實例分析

    ##這個SELECT2的執行流程如下:

    步驟1∶

    在執行SELECT語句時會又會單獨產生一個ReadView,該ReadView的trx_ids列表的內容就是[20],up_limit_id為20, low_limit_id為21, creator_trx_id為0。 步驟2:
    從版本鏈中挑選可見的記錄,從圖中看出,最新版本的列name的內容是‘宋八’,該版本的tr×_id值為20,在trx_ids列表內,所以不符合可見性要求,根據roll.pointer跳到下一個版本。 步驟3∶
    下一個版本的列name的內容是’錢七’,該版本的trx_id值為20,也在trx_ids列表內,所以也不符合要求,繼續跳到下一個版本。 步驟4∶下一個版本的列name的內容是’王五’,該版本的trx_id值為10,小於ReadView中的up_limit.id值20,所以這個版本是符合要求的,最後返回給使用者的版本就是這條列name為’王五’的記錄。 以此類推,如果之後事務id為20的記錄也提交了,再次在使用READ CONMMITTED隔離級別的事務中查詢表student中id值為1的記錄時,得到的結果就是‘宋八&rsquo ;了,具體流程我們就不分析了。

    5.2 REPEATABLE READ

    在隔離等級下:

    使用REPEATABLE READ隔離等級的交易來說,只會在第一次執行查詢語句時產生一個ReadView,之後的查詢就不會重複產生了。

    例如,系統裡有兩個交易id分別為10、20的交易在執行:

    此刻,表student中id为1的记录得到的版本链表如下所示:

    MySQL多版本並發控制MVCC實例分析

    假设现在有一个使用REPEATABLE READ隔离级别的事务开始执行:

    MySQL多版本並發控制MVCC實例分析

    此时执行过程与read committed相同

    MySQL多版本並發控制MVCC實例分析

    MySQL多版本並發控制MVCC實例分析

    然后再到刚才使用REPEATABLE READ隔离级别的事务中继续查找id为1的记录,如下:

    MySQL多版本並發控制MVCC實例分析

    这个SELECT2的执行过程如下:

    步骤1:因为当前事务的隔离级别为REPEATABLE READ,而之前在执行SELECT1时已经生成过ReadView了,所以此时直接复用之前的ReadView,之前的ReadView的trx_ids列表的内容就是[10,20],up_limit_id为10, low_limit_id为21 , creator_trx_id为0。
    步骤2:然后从版本链中挑选可见的记录,从图中可以看出,最新版本的列name的内容是’宋八’trx_id值为20,在trx_ids列表内,所以不符合可见性要求,根据roll_pointer跳到下一个版本。
    步骤3:下一个版本的列name的内容是’钱七’,该版本的trx_id值为20,也在trx_ids列表内合要求,继续跳到下一个版本。
    步骤4:下一个版本的列name的内容是’王五’,该版本的trx_id值为10,而trx_ids列表中是包含值为10的事务id的,所以该版本也不符合要求,同理下一个列name的内容是’李四’的版本也不符合要求。继续跳到下个版本。
    步聚5∶下一个版本的列name的内容是’张三’,该版本的trx_id值为80,小于Readview中的up_limit_id值10,所以这个版本是符合要求的,最后返回给用户的版本就是这条列c为‘张三’的记录。
    两次SELECT查询得到的结果是重复的,记录的列c值都是’张三’,这就是可重复读的含义。如果我们之后再把事务id为20的记录提交了,然后再到刚才使用REPEATABLE READ隔离级刷的事务中继续查找这个id为1的记录,得到的结果还是’张三’,具体执行过程大家可以自己分析一下。

    5.3 如何解决幻读

    假设现在表student中只有一条数据,数据内容中,主键id=1,隐藏的trx_id=10,它的undo log如下图所示。

    MySQL多版本並發控制MVCC實例分析

    假设现在有事务A和事务B并发执行,事务A的事务id为20,事务B的事务id为30。
    步骤1:事务A开始第一次查询数据,查询的SQL语句如下。

    select * from student where id > 1;

    在开始查询之前,MySQL会为事务A产生一个ReadView,此时ReadView的内容如下: trx_ids=[20, 30 ] ,up_limit_id=20 , low_limit_id=31 , creator_trx_id=20。

    因为表student只有一条符合条件 where id>=1 的数据,所以会被查询出来。然后根据ReadView机制,发现该行数据的trx_id=10,小于事务A的ReadView里up_limit_id,这表示这条数据是事务A开启之前,其他事务就已经提交了的数据,因此事务A可以读取到。

    结论:事务A的第一次查询,能读取到一条数据,id=1。

    步骤2∶接着事务B(trx_id=30),往表student中新插入两条数据,并提交事务。

    insert into student(id,name) values(2,'李四');
    insert into student(id,name) values(3,'王五');

    此时表student中就有三条数据了,对应的undo如下图所示:

    MySQL多版本並發控制MVCC實例分析

    步驟3∶接著事務A開啟第二次查詢,根據可重複讀取隔離等級的規則,此時事務A並不會再重新產生ReadView。此時表student中的3個資料都滿足 where id>=1的條件,因此會先查出來。然後根據ReadView機制,判斷每個資料是不是都可以被事務A看到。
    1)首先 id=1的這條數據,前面已經說過了,可以被事務A看到。
    2)接著是id=2的數據,它的trx_id=30,此時事務A發現,這個值處於up_limit_id和low_limit_id之間,因此還需要再判斷30是否處於trx_ids數組內。由於事務A的trx_ids=[20,30],因此在數組內,這表示id=2的這條資料是與事務A在同一時刻啟動的其他事務提交的,所以這條資料不能讓事務A看到。
    3)同理,id=3的這條資料, trx_id 也是30,因此也不能被事務A看見。

    MySQL多版本並發控制MVCC實例分析

    結論:最終交易A的第二次查詢,只能查詢出id=1的這條資料。這和事務A的第一次查詢的結果是一樣的,因此沒有出現幻讀現象,所以說在 MySQL的可重複續隔離等級下,不存在幻讀問題。

    以上是MySQL多版本並發控制MVCC實例分析的詳細內容。更多資訊請關注PHP中文網其他相關文章!

    陳述
    本文轉載於:亿速云。如有侵權,請聯絡admin@php.cn刪除
    說明InnoDB重做日誌和撤消日誌的作用。說明InnoDB重做日誌和撤消日誌的作用。Apr 15, 2025 am 12:16 AM

    InnoDB使用redologs和undologs確保數據一致性和可靠性。 1.redologs記錄數據頁修改,確保崩潰恢復和事務持久性。 2.undologs記錄數據原始值,支持事務回滾和MVCC。

    在解釋輸出(類型,鍵,行,額外)中要查找的關鍵指標是什麼?在解釋輸出(類型,鍵,行,額外)中要查找的關鍵指標是什麼?Apr 15, 2025 am 12:15 AM

    EXPLAIN命令的關鍵指標包括type、key、rows和Extra。 1)type反映查詢的訪問類型,值越高效率越高,如const優於ALL。 2)key顯示使用的索引,NULL表示無索引。 3)rows預估掃描行數,影響查詢性能。 4)Extra提供額外信息,如Usingfilesort提示需要優化。

    在解釋中使用臨時狀態以及如何避免它是什麼?在解釋中使用臨時狀態以及如何避免它是什麼?Apr 15, 2025 am 12:14 AM

    Usingtemporary在MySQL查詢中表示需要創建臨時表,常見於使用DISTINCT、GROUPBY或非索引列的ORDERBY。可以通過優化索引和重寫查詢避免其出現,提升查詢性能。具體來說,Usingtemporary出現在EXPLAIN輸出中時,意味著MySQL需要創建臨時表來處理查詢。這通常發生在以下情況:1)使用DISTINCT或GROUPBY時進行去重或分組;2)ORDERBY包含非索引列時進行排序;3)使用複雜的子查詢或聯接操作。優化方法包括:1)為ORDERBY和GROUPB

    描述不同的SQL交易隔離級別(讀取未讀取,讀取,可重複的讀取,可序列化)及其在MySQL/InnoDB中的含義。描述不同的SQL交易隔離級別(讀取未讀取,讀取,可重複的讀取,可序列化)及其在MySQL/InnoDB中的含義。Apr 15, 2025 am 12:11 AM

    MySQL/InnoDB支持四種事務隔離級別:ReadUncommitted、ReadCommitted、RepeatableRead和Serializable。 1.ReadUncommitted允許讀取未提交數據,可能導致臟讀。 2.ReadCommitted避免臟讀,但可能發生不可重複讀。 3.RepeatableRead是默認級別,避免臟讀和不可重複讀,但可能發生幻讀。 4.Serializable避免所有並發問題,但降低並發性。選擇合適的隔離級別需平衡數據一致性和性能需求。

    MySQL與其他數據庫:比較選項MySQL與其他數據庫:比較選項Apr 15, 2025 am 12:08 AM

    MySQL適合Web應用和內容管理系統,因其開源、高性能和易用性而受歡迎。 1)與PostgreSQL相比,MySQL在簡單查詢和高並發讀操作上表現更好。 2)相較Oracle,MySQL因開源和低成本更受中小企業青睞。 3)對比MicrosoftSQLServer,MySQL更適合跨平台應用。 4)與MongoDB不同,MySQL更適用於結構化數據和事務處理。

    MySQL索引基數如何影響查詢性能?MySQL索引基數如何影響查詢性能?Apr 14, 2025 am 12:18 AM

    MySQL索引基数对查询性能有显著影响:1.高基数索引能更有效地缩小数据范围,提高查询效率;2.低基数索引可能导致全表扫描,降低查询性能;3.在联合索引中,应将高基数列放在前面以优化查询。

    MySQL:新用戶的資源和教程MySQL:新用戶的資源和教程Apr 14, 2025 am 12:16 AM

    MySQL學習路徑包括基礎知識、核心概念、使用示例和優化技巧。 1)了解表、行、列、SQL查詢等基礎概念。 2)學習MySQL的定義、工作原理和優勢。 3)掌握基本CRUD操作和高級用法,如索引和存儲過程。 4)熟悉常見錯誤調試和性能優化建議,如合理使用索引和優化查詢。通過這些步驟,你將全面掌握MySQL的使用和優化。

    現實世界Mysql:示例和用例現實世界Mysql:示例和用例Apr 14, 2025 am 12:15 AM

    MySQL在現實世界的應用包括基礎數據庫設計和復雜查詢優化。 1)基本用法:用於存儲和管理用戶數據,如插入、查詢、更新和刪除用戶信息。 2)高級用法:處理複雜業務邏輯,如電子商務平台的訂單和庫存管理。 3)性能優化:通過合理使用索引、分區表和查詢緩存來提升性能。

    See all articles

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

    人工智慧驅動的應用程序,用於創建逼真的裸體照片

    AI Clothes Remover

    AI Clothes Remover

    用於從照片中去除衣服的線上人工智慧工具。

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    AI Hentai Generator

    AI Hentai Generator

    免費產生 AI 無盡。

    熱門文章

    R.E.P.O.能量晶體解釋及其做什麼(黃色晶體)
    4 週前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.最佳圖形設置
    4 週前By尊渡假赌尊渡假赌尊渡假赌
    R.E.P.O.如果您聽不到任何人,如何修復音頻
    4 週前By尊渡假赌尊渡假赌尊渡假赌
    WWE 2K25:如何解鎖Myrise中的所有內容
    1 個月前By尊渡假赌尊渡假赌尊渡假赌

    熱工具

    Atom編輯器mac版下載

    Atom編輯器mac版下載

    最受歡迎的的開源編輯器

    記事本++7.3.1

    記事本++7.3.1

    好用且免費的程式碼編輯器

    ZendStudio 13.5.1 Mac

    ZendStudio 13.5.1 Mac

    強大的PHP整合開發環境

    VSCode Windows 64位元 下載

    VSCode Windows 64位元 下載

    微軟推出的免費、功能強大的一款IDE編輯器

    WebStorm Mac版

    WebStorm Mac版

    好用的JavaScript開發工具