溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

MySQL多版本控制器MVCC的介紹

發(fā)布時(shí)間:2021-07-02 16:17:23 來源:億速云 閱讀:223 作者:chen 欄目:大數(shù)據(jù)

這篇文章主要介紹“MySQL多版本控制器MVCC的介紹”,在日常操作中,相信很多人在MySQL多版本控制器MVCC的介紹問題上存在疑惑,小編查閱了各式資料,整理出簡(jiǎn)單好用的操作方法,希望對(duì)大家解答”MySQL多版本控制器MVCC的介紹”的疑惑有所幫助!接下來,請(qǐng)跟著小編一起來學(xué)習(xí)吧!

    MySQl大多數(shù)事務(wù)性存儲(chǔ)引擎實(shí)現(xiàn)的都不是簡(jiǎn)單的行級(jí)鎖?;诟咝阅芸紤],他們一般都同時(shí)是想了多版本并發(fā)控制器(MVCC)。不僅僅MySQL,包括Oracle、PostgreSQL等其他數(shù)據(jù)庫系統(tǒng)也都實(shí)現(xiàn)了MVCC,但各自實(shí)現(xiàn)機(jī)制不盡相同,因?yàn)镸VCC沒有一個(gè)統(tǒng)一的實(shí)現(xiàn)標(biāo)準(zhǔn)。MVCC可以說是行級(jí)鎖的一個(gè)變種,但是他在多數(shù)情況下避免了加鎖操作,因此開銷更低。雖然實(shí)現(xiàn)機(jī)制有所不同,但大都實(shí)現(xiàn)了非阻塞的讀操作,寫操作也只鎖定必要的行。

MVCC只存在于MySQL的Read Commit和Read Repeatable的隔離級(jí)別下。

事務(wù)日志

    事務(wù)日志可以幫助提高事務(wù)的效率。使用事務(wù)日志,存儲(chǔ)引擎在修改表的數(shù)據(jù)時(shí)只需要修改其內(nèi)存拷貝,再把該修改行為記錄到持久在硬盤上的事務(wù)日志中,而不用每次都將修改的數(shù)據(jù)本身持久到磁盤。事務(wù)日志采用的是追加的方式,因此寫日志的操作是磁盤上一小塊區(qū)域內(nèi)的順序 I/O,而不像隨機(jī) I/O需要在次盤的多個(gè)地方移動(dòng)磁頭,所以采用事務(wù)日志的方式相對(duì)來說要快得多。事務(wù)日志持久以后,內(nèi)存中被修改的數(shù)據(jù)在后臺(tái)可以慢慢的刷回到磁盤。目前大多數(shù)存儲(chǔ)引擎都是這樣實(shí)現(xiàn)的,我們通常稱之為預(yù)寫式日志(Write-Ahead Logging),修改數(shù)據(jù)需要寫兩次磁盤。
    redo log 是InnoDB存儲(chǔ)引擎層的日志,主要用于記錄事務(wù)的日志信息,開啟一個(gè)事務(wù)時(shí),會(huì)記錄一個(gè)日志序列號(hào),當(dāng)事務(wù)執(zhí)行時(shí)會(huì)向日志緩沖(redo buffer)插入事務(wù)日志,并且在事務(wù)提交前會(huì)把redo buffer中的日志信息記錄到磁盤中。如數(shù)據(jù)庫掉電,InnoDB存儲(chǔ)引擎會(huì)使用redo log恢復(fù)到掉電前的時(shí)刻,以此來保證數(shù)據(jù)的完整性。
    undo log 是InnoDB存儲(chǔ)引擎層的日志,主要用于記錄數(shù)據(jù)被修改之前的日志,在表信息修改之前先會(huì)把數(shù)據(jù)拷貝到undo log 里,當(dāng)事務(wù)進(jìn)行回滾時(shí)可以通過undo log 里的日志進(jìn)行數(shù)據(jù)還原。
    undo log用于MVCC快照讀的數(shù)據(jù),在MVCC多版本控制中,通過讀取undo log的歷史版本數(shù)據(jù)可以實(shí)現(xiàn)不同事務(wù)版本號(hào)都擁有自己獨(dú)立的快照數(shù)據(jù)版本。有時(shí)候應(yīng)用到行版本控制的時(shí)候,也是通過undo log來實(shí)現(xiàn)的:當(dāng)讀取的某一行被其他事務(wù)鎖定時(shí),它可以從undo log中分析出該行記錄以前的數(shù)據(jù)是什么,從而提供該行版本信息,讓用戶實(shí)現(xiàn)非鎖定一致性讀取。

    InnoDB是一個(gè)多版本的存儲(chǔ)引擎:它保存有關(guān)已更改行的舊版本的信息,以支持并發(fā)和回滾等事務(wù)功能 。此信息存儲(chǔ)在表空間中稱為回滾段的數(shù)據(jù)結(jié)構(gòu)中(在Oracle中的類似數(shù)據(jù)結(jié)構(gòu)之后)。InnoDB 使用回滾段中的信息來執(zhí)行事務(wù)回滾中所需的撤消操作。它還使用該信息構(gòu)建行的早期版本以進(jìn)行一致讀取。
    在內(nèi)部,InnoDB為數(shù)據(jù)庫中存儲(chǔ)的每一行添加三個(gè)字段。6字節(jié)DB_TRX_ID字段指示插入或更新行的最后一個(gè)事務(wù)的事務(wù)標(biāo)識(shí)符。此外,刪除在內(nèi)部被視為更新,其中行中的特殊位被設(shè)置為將其標(biāo)記為已刪除。每行還包含一個(gè)DB_ROLL_PTR稱為滾動(dòng)指針的7字節(jié) 字段。roll指針指向?qū)懭牖貪L段的undo log記錄。如果更新了行,則undo log記錄包含在更新行之前重建行內(nèi)容所需的信息。一個(gè)6字節(jié)的DB_ROW_ID字段包含一個(gè)行ID,當(dāng)插入新行時(shí),該行ID會(huì)單調(diào)增加。如果 InnoDB自動(dòng)生成聚簇索引,索引包含行ID值。否則,該 DB_ROW_ID列不會(huì)出現(xiàn)在任何索引中。
    撤消段中的undo log分為插入和更新undo log。只在事務(wù)回滾中才需要插入undo log,并且可以在事務(wù)提交后立即丟棄。更新undo log也用于一致性讀取,但只有在沒有事務(wù)InnoDB已分配快照的情況下才能丟棄它們 ,在一致讀取中可能需要更新undo log中的信息來構(gòu)建數(shù)據(jù)庫的早期版本行。
    在InnoDB多版本控制方案中,使用SQL語句刪除行時(shí),不會(huì)立即從數(shù)據(jù)庫中物理刪除該行。InnoDB只有在丟棄為刪除寫入的更新undo log記錄時(shí),才會(huì)物理刪除相應(yīng)的行及其索引記錄。此刪除操作稱為purge,并且速度非???,通常與執(zhí)行刪除的SQL語句的時(shí)間順序相同。

  • DB_TRX_ID:記錄操作該數(shù)據(jù)事務(wù)的事務(wù)ID;

  • DB_ROLL_PTR:指向上一個(gè)版本數(shù)據(jù)在undo log 里的位置指針;

  • DB_ROW_ID: 隱藏ID ,當(dāng)創(chuàng)建表沒有合適的索引作為聚集索引時(shí),會(huì)用該隱藏ID創(chuàng)建聚集索引;

read view
    read view 其實(shí)就是一個(gè)保存事務(wù)ID的list列表。記錄的是本事務(wù)執(zhí)行時(shí),MySQL還有哪些事務(wù)在執(zhí)行。
    Read Repeatable 對(duì)應(yīng)的是在每個(gè)事務(wù)啟動(dòng)的時(shí)候創(chuàng)建一個(gè)read view。
    Read Commit 對(duì)應(yīng)的是每次執(zhí)行SQL statement時(shí)候創(chuàng)建一個(gè)read view。

  • Read View結(jié)構(gòu)

struct read_view_t{
	// 由于是逆序排列,所以low/up有所顛倒
	// 能看到當(dāng)前行版本的高水位標(biāo)識(shí),> low_limit_id皆不能看見
	trx_id_t	low_limit_id;
	// 能看到當(dāng)前行版本的低水位標(biāo)識(shí),< up_limit_id皆能看見
	trx_id_t	up_limit_id;
	// 當(dāng)前活躍事務(wù)(即未提交的事務(wù))的數(shù)量
	ulint		n_trx_ids;
	// 以逆序排列的當(dāng)前獲取活躍事務(wù)id的數(shù)組
	// 其up_limit_id<tx_id<low_limit_id
	trx_id_t*	trx_ids;	
	// 創(chuàng)建當(dāng)前視圖的事務(wù)id
	trx_id_t	creator_trx_id;
	// 事務(wù)系統(tǒng)中的一致性視圖鏈表
	UT_LIST_NODE_T(read_view_t) view_list;
};
  • 版本可見性

read view其實(shí)保存的是當(dāng)前活躍事務(wù)的所有事務(wù)id,如果當(dāng)前行版本對(duì)應(yīng)修改的事務(wù)id不在當(dāng)前活躍事務(wù)里面的話,表示當(dāng)前版本可見,否則就是不可見。也就是看不到read view創(chuàng)建以后啟動(dòng)的事務(wù),看不到read view創(chuàng)建時(shí)活躍的事務(wù)。Read View不可見的話,就從undo log中讀取。

只有在非鎖select下才會(huì)創(chuàng)建read view。

當(dāng)前讀和快照讀

  • 當(dāng)前讀

    當(dāng)前讀是讀取的數(shù)據(jù)庫最新的數(shù)據(jù),當(dāng)前讀和快照讀不同,因?yàn)橐x取最新的數(shù)據(jù)而且要保證事務(wù)的隔離性,所以當(dāng)前讀是需要對(duì)數(shù)據(jù)進(jìn)行加鎖的 (Update、    delete、    insert、   select ....lock in share mode、   select for update 為當(dāng)前讀)

  • 快照讀

    快照讀是指讀取數(shù)據(jù)時(shí)不是讀取最新版本的數(shù)據(jù),而是基于歷史版本讀取的一個(gè)快照信息(mysql讀取undo log歷史版本) ;
快照讀可以使普通的SELECT 讀取數(shù)據(jù)時(shí)不用對(duì)表數(shù)據(jù)進(jìn)行加鎖,從而解決了因?yàn)閷?duì)數(shù)據(jù)庫表的加鎖而導(dǎo)致的兩個(gè)如下問題:

  1.     解決了因加鎖導(dǎo)致的修改數(shù)據(jù)時(shí)無法對(duì)數(shù)據(jù)讀取問題;

  2.     解決了因加鎖導(dǎo)致讀取數(shù)據(jù)時(shí)無法對(duì)數(shù)據(jù)進(jìn)行修改的問題;

到此,關(guān)于“MySQL多版本控制器MVCC的介紹”的學(xué)習(xí)就結(jié)束了,希望能夠解決大家的疑惑。理論與實(shí)踐的搭配能更好的幫助大家學(xué)習(xí),快去試試吧!若想繼續(xù)學(xué)習(xí)更多相關(guān)知識(shí),請(qǐng)繼續(xù)關(guān)注億速云網(wǎng)站,小編會(huì)繼續(xù)努力為大家?guī)砀鄬?shí)用的文章!

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI