<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      深入解析:通用:MySQL-深入理解MySQL中的MVCC:原理、實現(xiàn)與實戰(zhàn)價值

      深入理解MySQL中的MVCC:原理、實現(xiàn)與實戰(zhàn)價值

      支撐高并發(fā)讀寫的核心技術(shù)。它解決了傳統(tǒng)鎖機制中“讀阻塞寫、寫阻塞讀”的痛點,讓數(shù)據(jù)庫在保證數(shù)據(jù)一致性的同時,能高效處理大量并發(fā)請求。本文將從定義、核心原理、實現(xiàn)組件、工作流程到實戰(zhàn)應(yīng)用,全方位拆解MVCC,幫你搞懂它在實際工作中的作用。就是在MySQL的InnoDB存儲引擎中,MVCC(Multi-Version Concurrency Control,多版本并發(fā)控制)

      什么?—— 從核心定義到解決的痛點就是一、MVCC

      1.1 核心定義

      MVCC本質(zhì)是一種“多版本數(shù)據(jù)管理策略”:InnoDB會為數(shù)據(jù)庫中的每條數(shù)據(jù)記錄維護多個版本,當事務(wù)對數(shù)據(jù)進行修改時,不會直接覆蓋原數(shù)據(jù),而是生成一個新的數(shù)據(jù)版本;同時,讀取數(shù)據(jù)時,會根據(jù)事務(wù)的“可見性規(guī)則”,選擇合適的歷史版本進行讀取。這種機制讓“讀運行”和“寫操作”可以并行執(zhí)行,互不阻塞。

      1.2 解決的核心痛點

      在沒有MVCC的傳統(tǒng)鎖機制中,并發(fā)場景會面臨嚴重的性能問題:

      • 讀阻塞寫:當事務(wù)A讀取某條資料時,會加共享鎖(S鎖),此時事務(wù)B要修改該內(nèi)容,需加排他鎖(X鎖),但S鎖和X鎖互斥,事務(wù)B會被阻塞;
      • 寫阻塞讀:當事務(wù)A修改數(shù)據(jù)加X鎖時,事務(wù)B讀取該數(shù)據(jù)需加S鎖,同樣會被阻塞。

      而MVCC依據(jù)“多版本”設(shè)計,讓讀操作讀取歷史版本,寫操作生成新版本,二者互不干擾。例如:

      • 事務(wù)A修改數(shù)據(jù)時,生成新版本并加X鎖;
      • 事務(wù)B讀取同一數(shù)據(jù)時,無需等待X鎖釋放,直接讀取未被修改的歷史版本;
      • 雙方并行執(zhí)行,既保證了數(shù)據(jù)一致性,又提升了并發(fā)效率。

      二、MVCC的核心原理:如何實現(xiàn)“多版本”與“可見性”?

      MVCC的實現(xiàn)依賴InnoDB的三大核心組件,以及一套嚴格的“可見性判斷規(guī)則”,這也是理解MVCC的關(guān)鍵。

      2.1 支撐MVCC的3個核心組件

      InnoDB通過以下三個組件,為MVCC給出“版本存儲”和“版本追溯”的基礎(chǔ),這些組件在之前的InnoDB架構(gòu)文章中已有提及,此處需結(jié)合MVCC重新梳理:

      1. 數(shù)據(jù)行的隱藏列

      InnoDB會為每一條數(shù)據(jù)記錄自動添加3個隱藏列,用于記錄版本信息:

      • DB_TRX_ID(事務(wù)ID):記錄最后一次修改該素材的事務(wù)ID(每個事務(wù)啟動時,InnoDB會分配一個全局唯一的遞增事務(wù)ID);
      • DB_ROLL_PTR(回滾指針):指向該信息的“上一個歷史版本”在Undo Log中的存儲地址,通過該指針,可串聯(lián)起該數(shù)據(jù)的所有歷史版本,形成一條“版本鏈”;
      • DB_ROW_ID(行ID):若表沒有顯式定義主鍵,InnoDB會用這個隱藏列作為默認主鍵,與MVCC直接關(guān)聯(lián)不大,但確保每行資料唯一。

      舉個例子:假設(shè)表user有一條初始數(shù)據(jù)(id=1, name="張三", age=20),其隱藏列初始狀態(tài)如下:

      idnameageDB_TRX_IDDB_ROLL_PTR
      1張三200NULL
      2. Undo Log(回滾日志)

      Undo Log不僅是事務(wù)回滾的依據(jù),也是MVCC存儲“歷史版本數(shù)據(jù)”的載體。當事務(wù)修改材料時,InnoDB會先將數(shù)據(jù)的“舊版本”寫入Undo Log,再修改當前數(shù)據(jù)并更新隱藏列:

      • 若事務(wù)執(zhí)行ROLLBACK,可通過Undo Log恢復(fù)舊版本;
      • 若其他事務(wù)需要讀取歷史版本,可通過DB_ROLL_PTR從Undo Log中獲取對應(yīng)版本數(shù)據(jù)。

      例如:事務(wù)1(TRX_ID=100)執(zhí)行UPDATE user SET age=21 WHERE id=1,InnoDB會:

      1. 將數(shù)據(jù)的舊版本(id=1, name="張三", age=20, DB_TRX_ID=0)寫入Undo Log;
      2. 修改當前數(shù)據(jù)的age為21,更新DB_TRX_ID=100DB_ROLL_PTR指向Undo Log中舊版本的地址;
        此時素材的版本鏈如下:
      • 當前版本:(age=21, DB_TRX_ID=100, DB_ROLL_PTR→Undo Log舊版本)
      • Undo Log中的歷史版本:(age=20, DB_TRX_ID=0, DB_ROLL_PTR=NULL)
      3. Read View(讀視圖)

      Read View是事務(wù)讀取數(shù)據(jù)時的“可見性判斷依據(jù)”,它本質(zhì)是一個“事務(wù)ID集合”,包含以下4個核心參數(shù):

      • m_low_limit_id:當前系統(tǒng)中“尚未分配的最小事務(wù)ID”(即下一個要啟動的事務(wù)ID);
      • m_up_limit_id:當前Read View中“已分配的最大事務(wù)ID”;
      • m_creator_trx_id:創(chuàng)建該Read View的事務(wù)ID(即當前讀取數(shù)據(jù)的事務(wù)ID);
      • m_ids:當前環(huán)境中“正在活躍的事務(wù)ID列表”(即已啟動但未提交的事務(wù)ID)。

      當事務(wù)讀取數(shù)據(jù)時,會通過Read View判斷數(shù)據(jù)版本的“可見性”—— 只有滿足規(guī)則的材料版本,才會被當前事務(wù)讀取。

      2.2 MVCC的可見性判斷規(guī)則

      事務(wù)讀取數(shù)據(jù)時,會從數(shù)據(jù)的“最新版本”開始,沿著DB_ROLL_PTR遍歷版本鏈,逐個判斷每個版本是否符合Read View的可見性規(guī)則,直到找到第一個“可見版本”。核心規(guī)則如下:

      1. 若當前版本的DB_TRX_ID = m_creator_trx_id:說明該版本是當前事務(wù)自己修改的,可見;
      2. 若當前版本的DB_TRX_ID < m_up_limit_id
        • 若DB_TRX_ID不在m_ids中(即修改該版本的事務(wù)已提交),可見;
        • 若DB_TRX_ID在m_ids中(即修改該版本的事務(wù)未提交),不可見,繼續(xù)遍歷歷史版本;
      3. 若當前版本的DB_TRX_ID >= m_low_limit_id:說明該版本是在當前Read View創(chuàng)建后生成的,不可見,繼續(xù)遍歷歷史版本;
      4. 若m_up_limit_id ≤ DB_TRX_ID < m_low_limit_id
        • 若DB_TRX_ID不在m_ids中,可見;
        • 若DB_TRX_ID在m_ids中,不可見,繼續(xù)遍歷歷史版本。

      簡單來說:只有“已提交事務(wù)修改的版本”或“當前事務(wù)自己修改的版本”,才對當前事務(wù)可見。

      三、MVCC的工作流程:結(jié)合實例看懂執(zhí)行過程

      為了更直觀理解MVCC,此處憑借一個“雙事務(wù)并發(fā)”的實例,拆解其完整工作流程。假設(shè)場景如下:

      • 初始數(shù)據(jù):user(id=1, name="張三", age=20, DB_TRX_ID=0, DB_ROLL_PTR=NULL)
      • 事務(wù)A(TRX_ID=100):執(zhí)行UPDATE user SET age=21 WHERE id=1,未提交;
      • 事務(wù)B(TRX_ID=200):執(zhí)行SELECT * FROM user WHERE id=1,讀取數(shù)據(jù)。

      步驟1:事務(wù)A修改材料,生成新版本

      1. 事務(wù)A啟動,InnoDB分配TRX_ID=100;
      2. 事務(wù)A執(zhí)行UPDATE操控:
        • 將原數(shù)據(jù)(age=20, DB_TRX_ID=0)寫入Undo Log;
        • 修改當前數(shù)據(jù)為(age=21, DB_TRX_ID=100, DB_ROLL_PTR→Undo Log舊版本);
      3. 事務(wù)A未提交,暫時持有數(shù)據(jù)的X鎖。

      步驟2:事務(wù)B讀取數(shù)據(jù),創(chuàng)建Read View

      1. 事務(wù)B啟動,InnoDB分配TRX_ID=200;
      2. 事務(wù)B執(zhí)行SELECT操作,InnoDB為其創(chuàng)建Read View,此時架構(gòu)中活躍事務(wù)只有A(TRX_ID=100),因此Read View參數(shù)為:
        • m_low_limit_id=201(下一個要分配的事務(wù)ID);
        • m_up_limit_id=200(當前已分配的最大事務(wù)ID);
        • m_creator_trx_id=200(事務(wù)B的ID);
        • m_ids=[100](活躍事務(wù)ID列表)。

      步驟3:事務(wù)B判斷版本可見性,讀取歷史版本

      1. 事務(wù)B首先讀取數(shù)據(jù)的“最新版本”(age=21,DB_TRX_ID=100);
      2. 按照可見性規(guī)則判斷:
        • DB_TRX_ID=100 < m_up_limit_id=200,但100在m_ids(活躍事務(wù)列表)中,說明修改該版本的事務(wù)A未提交,此版本不可見;
      3. 沿著DB_ROLL_PTR遍歷歷史版本,讀取Undo Log中的舊版本(age=20,DB_TRX_ID=0);
      4. 再次判斷:
        • DB_TRX_ID=0 < m_up_limit_id=200,且0不在m_ids中(事務(wù)已提交,實際是初始狀態(tài)),此版本可見;
      5. 事務(wù)B返回該可見版本的數(shù)據(jù):(id=1, name="張三", age=20)。

      步驟4:事務(wù)A提交后,事務(wù)B再次讀取

      1. 事務(wù)A提交,釋放X鎖,此時數(shù)據(jù)的最新版本(age=21,DB_TRX_ID=100)變?yōu)椤耙烟峤粻顟B(tài)”;
      2. 事務(wù)B再次執(zhí)行SELECT操作(若事務(wù)B未結(jié)束,InnoDB不會重新創(chuàng)建Read View,仍使用之前的Read View):
        • 再次讀取最新版本(age=21,DB_TRX_ID=100);
        • 按原Read View判斷:100仍在m_ids中(Read View未更新),此版本仍不可見;
        • 繼續(xù)讀取歷史版本(age=20),返回結(jié)果不變。

      這也解釋了InnoDB在“可重復(fù)讀(Repeatable Read)”隔離級別下,“事務(wù)內(nèi)多次讀取同一數(shù)據(jù),結(jié)果一致”的原因——Read View在事務(wù)首次讀取時創(chuàng)建,后續(xù)不會更新。

      四、MVCC與事務(wù)隔離級別的關(guān)聯(lián)

      MVCC的行為會隨InnoDB的事務(wù)隔離級別變化,核心差異在于“Read View的創(chuàng)建時機”不同,這直接影響讀取數(shù)據(jù)的可見性。InnoDB支持的4個隔離級別中,與MVCC相關(guān)的是“讀已提交(Read Committed)”和“可重復(fù)讀(Repeatable Read)”(另外兩個級別“讀未提交”不判斷版本可見性,“串行化”用鎖代替MVCC)。

      4.1 讀已提交(Read Committed):每次讀取都創(chuàng)建新Read View

      • Read View創(chuàng)建時機:事務(wù)中每次執(zhí)行SELECT操作時,都會重新創(chuàng)建一個新的Read View;
      • 核心特點:能看到“當前時間點已提交的所有事務(wù)修改的版本”,避免“不可重復(fù)讀”;
      • 實例驗證
        1. 事務(wù)A(TRX_ID=100)修改數(shù)據(jù)為age=21,未提交;
        2. 事務(wù)B(TRX_ID=200)首次SELECT,創(chuàng)建Read View(m_ids=[100]),讀取到age=20;
        3. 事務(wù)A提交,數(shù)據(jù)最新版本變?yōu)?code>age=21(已提交);
        4. 事務(wù)B再次SELECT,重新創(chuàng)建Read View(此時m_ids為空),讀取最新版本age=21;
          結(jié)果:事務(wù)B兩次讀取結(jié)果不同,符合“讀已提交”的特性。

      4.2 可重復(fù)讀(Repeatable Read):事務(wù)首次讀取時創(chuàng)建Read View

      • Read View創(chuàng)建時機:事務(wù)中首次執(zhí)行SELECT操作時創(chuàng)建Read View,后續(xù)所有SELECT都復(fù)用Read View;
      • 核心特點:事務(wù)內(nèi)多次讀取同一數(shù)據(jù),結(jié)果一致,避免“不可重復(fù)讀”和“幻讀”(InnoDB通過間隙鎖輔助解除幻讀);
      • 實例驗證
        1. 事務(wù)A(TRX_ID=100)修改數(shù)據(jù)為age=21提交;
        2. 事務(wù)B(TRX_ID=200)首次SELECT,創(chuàng)建Read View(m_ids=[100]),讀取到age=20;
        3. 事務(wù)A提交,數(shù)據(jù)最新版本變?yōu)閍ge=21(已提交);
        4. 事務(wù)B再次SELECT,復(fù)用原Read View(m_ids仍為[100]),仍讀取到age=20;
          結(jié)果:事務(wù)B兩次讀取結(jié)果一致,符合“可重復(fù)讀”的特性(MySQL默認隔離級別)。

      五、MVCC的實戰(zhàn)價值:工作中需要注意的點

      MVCC縱然提升了并發(fā)性能,但在實際工作中,若使用不當,可能會引發(fā)性能挑戰(zhàn)或數(shù)據(jù)一致性風(fēng)險,需注意以下幾點:

      5.1 長事務(wù)會導(dǎo)致Undo Log膨脹

      由于MVCC依賴Undo Log存儲歷史版本,若存在“長事務(wù)”(如事務(wù)啟動后長時間不提交),InnoDB無法回收該事務(wù)可見的歷史版本對應(yīng)的Undo Log,會導(dǎo)致Undo Log文件持續(xù)增大,占用磁盤空間,同時也會增加版本鏈遍歷的時間,影響讀性能。

      解決方案

      • 嚴格控制事務(wù)時長,避免在事務(wù)中包含用戶交互(如等待用戶輸入);
      • 定期監(jiān)控長事務(wù),通過information_schema.innodb_trx表查看未提交的事務(wù):
        SELECT trx_id, trx_started, trx_state, trx_query
        FROM information_schema.innodb_trx
        WHERE TIMESTAMPDIFF(SECOND, trx_started, NOW()) > 60; -- 查找運行超過60秒的事務(wù)

      5.2 合理選擇隔離級別,平衡一致性與性能

      • 讀已提交(Read Committed):適合對“數(shù)據(jù)一致性要求不高,但并發(fā)性能要求高”的場景(如電商商品列表查詢),Read View每次創(chuàng)建,能及時看到已提交的新數(shù)據(jù),且鎖爭用少;

      • 可重復(fù)讀(Repeatable Read):適合對“數(shù)據(jù)一致性要求高”的場景(如金融交易、訂單支付),但長事務(wù)下可能因Undo Log膨脹影響性能。

      常見誤解“數(shù)據(jù)一致性要求高 = 實時看到最新數(shù)據(jù)”??
      很多人覺得 “場景寫反”,本質(zhì)是陷入了一個誤解:把 “數(shù)據(jù)一致性” 等同于 “實時看到最新數(shù)據(jù)”。但實際上,業(yè)務(wù)場景中的 “一致性需求”,核心是 “業(yè)務(wù)邏輯執(zhí)行過程中,數(shù)據(jù)不會被意外修改導(dǎo)致邏輯混亂”,而非 “必須看到每一刻的最新數(shù)據(jù)”。?
      舉個更直觀的例子:?
      場景 1(商品列表):用戶看的是 “快照數(shù)據(jù)”,即使有延遲或變化,不影響核心體驗;?
      “流程化邏輯”,數(shù)據(jù)必須在整個流程中保持穩(wěn)定,否則邏輯會崩潰。?就是場景 2(訂單支付):框架執(zhí)行的

      注意:若使用“可重復(fù)讀”級別,需避免長事務(wù);若業(yè)務(wù)允許,可將非核心查詢的隔離級別降為“讀已提交”,提升性能。

      5.3 理解MVCC與鎖的關(guān)系:并非替代鎖

      MVCC主導(dǎo)解決“讀-寫并發(fā)”的阻塞問題,但“寫-寫并發(fā)”仍需依賴鎖機制:

      • 當兩個事務(wù)同時修改同一條數(shù)據(jù)時,仍會通過排他鎖(X鎖)互斥,避免數(shù)據(jù)沖突;
      • MVCC與鎖機制是“互補關(guān)系”:MVCC處理讀-寫并發(fā),鎖處理寫-寫并發(fā),共同保障InnoDB的高并發(fā)能力。

      六、總結(jié)

      對比維度讀已提交(Read Committed)可重復(fù)讀(Repeatable Read)
      Read View 創(chuàng)建時機每次執(zhí)行 SELECT 時重新創(chuàng)建事務(wù)首次 SELECT 時創(chuàng)建,后續(xù)復(fù)用
      一致性保障范圍僅避免 “臟讀”,不避免 “不可重復(fù)讀”避免 “臟讀”+“不可重復(fù)讀”,配合間隙鎖避免 “幻讀”
      信息版本可見性能看到 “當前時間點已提交的所有數(shù)據(jù)版本”(實時性強)僅能看到 “事務(wù)首次讀時已提交的版本”(版本固定)
      性能損耗點鎖爭用少(無間隙鎖)、Undo Log 回收快(版本鏈短)鎖爭用多(有間隙鎖)、Undo Log 回收慢(版本鏈長)

      MVCC是InnoDB實現(xiàn)高并發(fā)讀寫的核心技術(shù),其本質(zhì)是通過“多版本數(shù)據(jù)”和“可見性判斷”,讓讀操作與寫操作并行執(zhí)行。理解MVCC,需要掌握三個核心:

      1. 組件:數(shù)據(jù)行隱藏列(版本標識)、Undo Log(版本存儲)、Read View(可見性判斷);
      2. 規(guī)則:基于Read View的版本可見性判斷邏輯;
      3. 隔離級別關(guān)聯(lián):Read View的創(chuàng)建時機決定了隔離級別的行為。

      在實際工作中,合理利用MVCC的特性(如選擇合適的隔離級別),規(guī)避長事務(wù)導(dǎo)致的Undo Log膨脹問題,能讓InnoDB更好地支撐高并發(fā)業(yè)務(wù)。無論是開發(fā)工程師寫SQL,還是DBA做性能調(diào)優(yōu),理解MVCC都是必備的基礎(chǔ)能力。


      Studying will never be ending.

      ▲如有紕漏,煩請指正~~

      posted @ 2025-11-04 13:09  yangykaifa  閱讀(13)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 91亚洲国产成人精品性色| 亚洲偷自拍另类一区二区| 这里只有精品在线播放| 97精品人妻系列无码人妻| 成人一区二区三区久久精品| 国产精品高清一区二区不卡| 永定县| 少妇熟女天堂网av| 日本一区不卡高清更新二区| 女厕偷窥一区二区三区| 久热这里只有精品12| 国产精品美女AV免费观看| 国产精品美女久久久久久麻豆| 农村妇女野外一区二区视频| 国产精品一区二区日韩精品| 国产草草影院ccyycom| 国产精品亚洲综合久久小说| аⅴ天堂中文在线网| 一区二区在线观看 激情| 91福利国产成人精品导航| 亚洲熟妇少妇任你躁在线观看无码| 亚洲国产青草衣衣一二三区| 国产日韩AV免费无码一区二区三区| 日韩黄色av一区二区三区 | 国产成人精品一区二三区在线观看| 国产高在线精品亚洲三区| 草裙社区精品视频播放| 欧美交A欧美精品喷水| 国产午夜福利视频一区二区| 久久婷婷综合色丁香五月| 成在线人免费视频| 宣化县| 亚洲爆乳WWW无码专区| 人妻无码久久久久久久久久久| 日日噜噜夜夜狠狠视频| 中文字幕久久精品波多野结 | 四虎影视4hu4虎成人| 国产精品成人99一区无码| 永久无码天堂网小说区| 国产一区二区三区在线观看免费| 四虎在线成人免费观看|