日本免费高清视频-国产福利视频导航-黄色在线播放国产-天天操天天操天天操天天操|www.shdianci.com

學(xué)無(wú)先后,達(dá)者為師

網(wǎng)站首頁(yè) 編程語(yǔ)言 正文

MVCC和BufferPool緩存機(jī)制

作者:jakiechaipush 更新時(shí)間: 2023-10-15 編程語(yǔ)言

文章目錄

    • 1. MVCC多版本并發(fā)控制機(jī)制
    • 2. BufferPool緩存機(jī)制

1. MVCC多版本并發(fā)控制機(jī)制

Mysql可以在可重復(fù)讀隔離級(jí)別下可以保證事務(wù)較高的隔離性,這個(gè)隔離性是由MVCC機(jī)制來(lái)保證的,對(duì)一行數(shù)據(jù)的讀和寫(xiě)兩個(gè)操作默認(rèn)是不會(huì)通過(guò)加鎖互斥來(lái)保證隔離性,避免了頻繁加鎖互斥,而在Mysql在讀已提交和可重復(fù)讀隔離級(jí)別下都實(shí)現(xiàn)了MVCC機(jī)制。
undo日志版本鏈與read view機(jī)制詳解
undo日志版本鏈?zhǔn)侵敢恍袛?shù)據(jù)被多個(gè)事務(wù)依次修改過(guò)后,在每個(gè)事務(wù)修改完后,Mysql會(huì)保留修改前的數(shù)據(jù)undo回滾日志,并且用兩個(gè)隱藏字段trx_id(事務(wù)ID)和roll_pointer(會(huì)滾指針)把這些undo日志串聯(lián)起來(lái)形成一個(gè)歷史記錄版本鏈。

trx_id:表示對(duì)數(shù)據(jù)修改的事務(wù)的ID
roll_pointer:指向被修改數(shù)據(jù)的上一個(gè)版本

在可重復(fù)讀隔離級(jí)別,當(dāng)事務(wù)開(kāi)啟,執(zhí)行任何查詢sql時(shí)會(huì)生成當(dāng)前事務(wù)的一致性視圖read-view,該視圖在事務(wù)結(jié)束之前都不會(huì)變化(如果是讀已提交隔離級(jí)別在每次執(zhí)行查詢sql時(shí)都會(huì)重新生成),這個(gè)視圖由執(zhí)行查詢時(shí)所有未提交事 id數(shù)組(數(shù)組里最小的id為min_id)和已創(chuàng)建的最大事務(wù)id(max_id)組成,事務(wù)里的任何sql查詢結(jié)果需要從對(duì)應(yīng)版本鏈里的最新數(shù)據(jù)開(kāi)始逐條跟read-view做比對(duì)從而得到最終的快照結(jié)果。

注意:begin/start transaction命令并不是一個(gè)事務(wù)的起點(diǎn),在執(zhí)行到它們之后的第一個(gè)修改操作InnoDB表的語(yǔ)句時(shí)事務(wù)才算是真正的啟動(dòng),此時(shí)事務(wù)會(huì)向Mysql申請(qǐng)事務(wù)ID,mysql內(nèi)部是嚴(yán)格按照事務(wù)的啟動(dòng)順序來(lái)分配事務(wù)ID的

在這里插入圖片描述

版本鏈比對(duì)規(guī)則:

  1. 如果 row 的 trx_id 落在綠色部分( trx_id<min_id ),表示這個(gè)版本是已提交的事務(wù)生成的,這個(gè)數(shù)據(jù)是可見(jiàn)的;
  2. 如果 row 的 trx_id 落在紅色部分( trx_id>max_id ),表示這個(gè)版本是由將來(lái)啟動(dòng)的事務(wù)生成的,是不可見(jiàn)的(若 row 的 trx_id 就是當(dāng)前自己的事務(wù)是可見(jiàn)的);
  3. 如果 row 的 trx_id 落在黃色部分(min_id <=trx_id<= max_id),那就包括兩種情況
    a. 若 row 的 trx_id 在視圖數(shù)組中,表示這個(gè)版本是由還沒(méi)提交的事務(wù)生成的,不可見(jiàn)(若 row 的 trx_id 就是當(dāng)前自
    己的事務(wù)是可見(jiàn)的);
    b. 若 row 的 trx_id 不在視圖數(shù)組中,表示這個(gè)版本是已經(jīng)提交了的事務(wù)生成的,可見(jiàn)。

read-view執(zhí)行原理案例分析
這里首先列出了五個(gè)事務(wù)的sql語(yǔ)句執(zhí)行情況,如下:
在這里插入圖片描述

由上圖可見(jiàn),總共有五個(gè)事務(wù),事務(wù)的id為100,200,300,1,2,下面我們就來(lái)逐步分析:

  1. 首先事務(wù)300執(zhí)行update account set name = 'lilei300' where id = 1;然后提交。接著事務(wù)ID為1的事務(wù)執(zhí)行select name from account where id = 1;

我們可以很簡(jiǎn)單的看出查詢結(jié)果為lilei300,那為什么會(huì)是lilei300。首先我們可以看出此時(shí)的undo.log的日志版本鏈的情況是這樣的:

在這里插入圖片描述

其中藍(lán)色為最新的數(shù)據(jù),紅色為老數(shù)據(jù)。然后mysql會(huì)維護(hù)一個(gè)事務(wù)集,如下:

在這里插入圖片描述

然后mysql會(huì)從日志版本鏈的最新的數(shù)據(jù)開(kāi)始向下遍歷,這個(gè)例子先從上面第一個(gè)藍(lán)色的開(kāi)始,取出其事務(wù)ID為300,到事務(wù)集合中去比對(duì),發(fā)現(xiàn)位于黃色的區(qū)域(即有可能還是未提交),然后判斷是否在事務(wù)ID的read-view數(shù)組中(該數(shù)組前面說(shuō)過(guò)是由活躍事務(wù)的ID數(shù)組以及最大已提交事務(wù)組成),目前由第一張事務(wù)的執(zhí)行情況圖我們可以看出,目前事務(wù)ID為1的read-view為[100,200],300構(gòu)成,而300沒(méi)在read-view的活躍數(shù)組中,所以300對(duì)數(shù)據(jù)進(jìn)行的更改對(duì)事務(wù)1是可見(jiàn)的,所以日志版本鏈就不需要向下遍歷了,查詢的結(jié)果即為lilei300。

  1. 然后ID為100的事務(wù)又執(zhí)行了兩條更新語(yǔ)句,分別為update account set name = 'lilei1' where id = 1;update account set name = 'lilei2' where id = 1;,接著ID為1的事務(wù)再次執(zhí)行了查詢select name from account where id = 1;

同樣從會(huì)滾日子鏈開(kāi)始分析,藍(lán)色同樣為最新的數(shù)據(jù),紅色為老數(shù)據(jù),目前的日子版本鏈的情況如下所示:

在這里插入圖片描述

首先從最新的數(shù)據(jù)開(kāi)始便利日志版本鏈,首先拿到ID為100的數(shù)據(jù),比對(duì)事務(wù)集合,其同樣落在黃色區(qū)域,然后事務(wù)ID1比較其readview,發(fā)現(xiàn)其落在了活躍數(shù)組[100,200]中(注意除非一些特殊情況ID為1的事務(wù)對(duì)數(shù)據(jù)進(jìn)行了一些修改,其readview在整個(gè)過(guò)程中一般是不變的,雖然每次執(zhí)行一次查詢語(yǔ)句都會(huì)重新生成read-view),所以其對(duì)ID為1的事務(wù)是不可見(jiàn)的。然后接著向下遍歷,知道遍歷到ID為300的事務(wù),發(fā)現(xiàn)其是可見(jiàn)的,所以查詢到的數(shù)據(jù)同樣是lilei300。后面的過(guò)程同樣是按照這個(gè)過(guò)程分析。

mysql通過(guò)這個(gè)機(jī)制在RR隔離級(jí)別下實(shí)現(xiàn)了事務(wù)的可重復(fù)讀而不用加鎖。而在讀已提交的情況下Mysql同樣實(shí)現(xiàn)了MVCC機(jī)制,不同于RR級(jí)別,在讀已提交的隔離級(jí)別下,每當(dāng)一個(gè)事務(wù)被提交,其它事務(wù)相應(yīng)的read-view會(huì)及時(shí)更新。

2. BufferPool緩存機(jī)制

InnoDB引擎SQL執(zhí)行的BufferPool緩存機(jī)制如下所示:

在這里插入圖片描述
對(duì)上圖進(jìn)行分析:

  1. 首先客戶端執(zhí)行sql語(yǔ)句update t set name='zhuge666' where id=1
  2. 然后經(jīng)過(guò)連接器進(jìn)行客戶端的權(quán)限驗(yàn)證(判斷該客戶端是否有修改該條數(shù)據(jù)的權(quán)限)
  3. 然后通過(guò)分析器對(duì)sql語(yǔ)句進(jìn)行詞法分析
  4. 接著經(jīng)過(guò)優(yōu)化器來(lái)生成sql執(zhí)行計(jì)劃以及選擇合適的索引
  5. 最后來(lái)到執(zhí)行器開(kāi)始真正執(zhí)行sql(InnoDB層)
  • 首先InnoDB會(huì)將id為1的數(shù)據(jù)所在的頁(yè)加載到BufferPool中
  • 然后將要更新的那條數(shù)據(jù)舊的值寫(xiě)入到undo日志中(用于后期會(huì)滾)
  • 然后更新BufferPool中的緩存數(shù)據(jù)
  • 然后將更新情況寫(xiě)入到redo日志緩存中
  • 客戶端準(zhǔn)備提交事務(wù)
  • 首先redo日志寫(xiě)入到磁盤(pán)
  • binlog(主要用于回復(fù)數(shù)據(jù)庫(kù)磁盤(pán)中的數(shù)據(jù))日志寫(xiě)入磁盤(pán)
  • 寫(xiě)入commit標(biāo)記到redo日志文件中,提交事務(wù)完成,該標(biāo)記為了保證事務(wù)提交后redo于binlog日志的一致性。
  • Mysql后臺(tái)IO線程隨機(jī)以page為單位將更新后的數(shù)據(jù)寫(xiě)入到磁盤(pán)

以上便是該sql語(yǔ)句執(zhí)行的整個(gè)過(guò)程,但對(duì)于上面的過(guò)程可能還會(huì)存在下面這些問(wèn)題:

  1. InnoDB體系結(jié)構(gòu)是什么樣子的?
    在這里插入圖片描述
    InnoDB存儲(chǔ)引擎有多個(gè)內(nèi)存塊,可以認(rèn)為這些內(nèi)存塊共同組成了一個(gè)大的內(nèi)存池,負(fù)責(zé)如下工作:
  • 維護(hù)所有進(jìn)程/線程需要訪問(wèn)多個(gè)內(nèi)部數(shù)據(jù)結(jié)構(gòu)
  • 緩沖磁盤(pán)上的數(shù)據(jù),方便快速讀取(bufferPool),同時(shí)在對(duì)磁盤(pán)文件的數(shù)據(jù)修改之前在這里緩存
  • 重做日志緩存(redo.log)

后臺(tái)線程的主要作用是負(fù)責(zé)刷新內(nèi)存池中的數(shù)據(jù),保證緩沖池中的內(nèi)存緩存是最近的數(shù)據(jù)。此外將修改的數(shù)據(jù)文件刷新到磁盤(pán)文件,同時(shí)保證在數(shù)據(jù)庫(kù)發(fā)生異常的情況下InnoDB能夠恢復(fù)到正常運(yùn)行的狀態(tài)。

  1. Mysql的bufferpool的組成?

在這里插入圖片描述
3. Mysql是如何對(duì)緩沖池進(jìn)行管理?

通常來(lái)說(shuō)數(shù)據(jù)庫(kù)中的緩沖池是通過(guò)LRU算法來(lái)進(jìn)行管理的,即最頻繁使用的頁(yè)在LRU列表的前端,而最少使用的頁(yè)在LRU列表的尾端。但I(xiàn)nnoDB使用的并不是樸素的LRU算法,而是在LRU列表中加入了midpoint的位置,midpoint將LRU列表的數(shù)據(jù)頁(yè)分為熱數(shù)據(jù)和冷數(shù)據(jù)兩部分。(這部分還是比較復(fù)雜的)

  1. rode日志的刷新時(shí)機(jī)?
  • Master Thread每一秒將重做日志緩存刷新到重做日志文件
  • 每個(gè)事務(wù)提交時(shí)會(huì)將重做日志緩存刷新到重做日志文件
  • 當(dāng)重做日志緩存剩余空間下雨1/2時(shí),重做日志緩存刷新到重做日志文件
  1. 為什么Mysql不能直接更新磁盤(pán)上的數(shù)據(jù)而且設(shè)置這么一套復(fù)雜的機(jī)制來(lái)執(zhí)行SQL了?

因?yàn)閬?lái)一個(gè)請(qǐng)求就直接對(duì)磁盤(pán)文件進(jìn)行隨機(jī)讀寫(xiě),然后更新磁盤(pán)文件里的數(shù)據(jù)性能可能相當(dāng)差。因?yàn)榇疟P(pán)隨機(jī)讀寫(xiě)的性能是非常差的,所以直接更新磁盤(pán)文件是不能讓數(shù)據(jù)庫(kù)抗住很高并發(fā)的。 Mysql這套機(jī)制看起來(lái)復(fù)雜,但它可以保證每個(gè)更新請(qǐng)求都是更新內(nèi)存BufferPool,然后順序?qū)懭罩疚募瑫r(shí)還能保證各種異常情況下的數(shù)據(jù)一致性。 更新內(nèi)存的性能是極高的,然后順序?qū)懘疟P(pán)上的日志文件的性能也是非常高的,要遠(yuǎn)高于隨機(jī)讀寫(xiě)磁盤(pán)文件。 正是通過(guò)這套機(jī)制,才能讓我們的MySQL數(shù)據(jù)庫(kù)在較高配置的機(jī)器上每秒可以抗下幾千的讀寫(xiě)請(qǐng)求。

原文鏈接:https://blog.csdn.net/qq_43456605/article/details/133577606

  • 上一篇:沒(méi)有了
  • 下一篇:沒(méi)有了
欄目分類
最近更新