目錄
1.什麼是MVCC
2快照讀取與目前讀取
2.1 快照讀
2.2目前讀
3.複習
3.1 再談隔離等級
3.2 隱藏欄位、Undo Log版本鏈
#4、MVCC實作原理之ReadView
4.1什麼是ReadView
4.2 設計想法
4.3 ReadView的規則
5.舉例說明
5.3 如何解决幻读
首頁 資料庫 mysql教程 MySQL多版本並發控制MVCC實例分析

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

Jun 03, 2023 am 11:51 AM
mysql mvcc

    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

    熱AI工具

    Undresser.AI Undress

    Undresser.AI Undress

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

    AI Clothes Remover

    AI Clothes Remover

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

    Undress AI Tool

    Undress AI Tool

    免費脫衣圖片

    Clothoff.io

    Clothoff.io

    AI脫衣器

    Video Face Swap

    Video Face Swap

    使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

    熱門文章

    <🎜>:泡泡膠模擬器無窮大 - 如何獲取和使用皇家鑰匙
    3 週前 By 尊渡假赌尊渡假赌尊渡假赌
    北端:融合系統,解釋
    3 週前 By 尊渡假赌尊渡假赌尊渡假赌
    Mandragora:巫婆樹的耳語 - 如何解鎖抓鉤
    3 週前 By 尊渡假赌尊渡假赌尊渡假赌

    熱工具

    記事本++7.3.1

    記事本++7.3.1

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

    SublimeText3漢化版

    SublimeText3漢化版

    中文版,非常好用

    禪工作室 13.0.1

    禪工作室 13.0.1

    強大的PHP整合開發環境

    Dreamweaver CS6

    Dreamweaver CS6

    視覺化網頁開發工具

    SublimeText3 Mac版

    SublimeText3 Mac版

    神級程式碼編輯軟體(SublimeText3)

    熱門話題

    Java教學
    1666
    14
    CakePHP 教程
    1425
    52
    Laravel 教程
    1327
    25
    PHP教程
    1273
    29
    C# 教程
    1253
    24
    laravel入門實例 laravel入門實例 Apr 18, 2025 pm 12:45 PM

    Laravel 是一款 PHP 框架,用於輕鬆構建 Web 應用程序。它提供一系列強大的功能,包括:安裝: 使用 Composer 全局安裝 Laravel CLI,並在項目目錄中創建應用程序。路由: 在 routes/web.php 中定義 URL 和處理函數之間的關係。視圖: 在 resources/views 中創建視圖以呈現應用程序的界面。數據庫集成: 提供與 MySQL 等數據庫的開箱即用集成,並使用遷移來創建和修改表。模型和控制器: 模型表示數據庫實體,控制器處理 HTTP 請求。

    MySQL和PhpMyAdmin:核心功能和功能 MySQL和PhpMyAdmin:核心功能和功能 Apr 22, 2025 am 12:12 AM

    MySQL和phpMyAdmin是強大的數據庫管理工具。 1)MySQL用於創建數據庫和表、執行DML和SQL查詢。 2)phpMyAdmin提供直觀界面進行數據庫管理、表結構管理、數據操作和用戶權限管理。

    MySQL與其他編程語言:一種比較 MySQL與其他編程語言:一種比較 Apr 19, 2025 am 12:22 AM

    MySQL与其他编程语言相比,主要用于存储和管理数据,而其他语言如Python、Java、C 则用于逻辑处理和应用开发。MySQL以其高性能、可扩展性和跨平台支持著称,适合数据管理需求,而其他语言在各自领域如数据分析、企业应用和系统编程中各有优势。

    解決數據庫連接問題:使用minii/db庫的實際案例 解決數據庫連接問題:使用minii/db庫的實際案例 Apr 18, 2025 am 07:09 AM

    在開發一個小型應用時,我遇到了一個棘手的問題:需要快速集成一個輕量級的數據庫操作庫。嘗試了多個庫後,我發現它們要么功能過多,要么兼容性不佳。最終,我找到了minii/db,這是一個基於Yii2的簡化版本,完美地解決了我的問題。

    laravel框架安裝方法 laravel框架安裝方法 Apr 18, 2025 pm 12:54 PM

    文章摘要:本文提供了詳細分步說明,指導讀者如何輕鬆安裝 Laravel 框架。 Laravel 是一個功能強大的 PHP 框架,它 упростил 和加快了 web 應用程序的開發過程。本教程涵蓋了從系統要求到配置數據庫和設置路由等各個方面的安裝過程。通過遵循這些步驟,讀者可以快速高效地為他們的 Laravel 項目打下堅實的基礎。

    解決MySQL模式問題:TheliaMySQLModesChecker模塊的使用體驗 解決MySQL模式問題:TheliaMySQLModesChecker模塊的使用體驗 Apr 18, 2025 am 08:42 AM

    在使用Thelia開發電商網站時,我遇到了一個棘手的問題:MySQL模式設置不當,導致某些功能無法正常運行。經過一番探索,我找到了一個名為TheliaMySQLModesChecker的模塊,它能夠自動修復Thelia所需的MySQL模式,徹底解決了我的困擾。

    MySQL:結構化數據和關係數據庫 MySQL:結構化數據和關係數據庫 Apr 18, 2025 am 12:22 AM

    MySQL通過表結構和SQL查詢高效管理結構化數據,並通過外鍵實現表間關係。 1.創建表時定義數據格式和類型。 2.使用外鍵建立表間關係。 3.通過索引和查詢優化提高性能。 4.定期備份和監控數據庫確保數據安全和性能優化。

    MySQL:解釋的關鍵功能和功能 MySQL:解釋的關鍵功能和功能 Apr 18, 2025 am 12:17 AM

    MySQL是一個開源的關係型數據庫管理系統,廣泛應用於Web開發。它的關鍵特性包括:1.支持多種存儲引擎,如InnoDB和MyISAM,適用於不同場景;2.提供主從復制功能,利於負載均衡和數據備份;3.通過查詢優化和索引使用提高查詢效率。

    See all articles