您好,登錄后才能下訂單哦!
這篇文章主要介紹“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è)如下問題:
解決了因加鎖導(dǎo)致的修改數(shù)據(jù)時(shí)無法對(duì)數(shù)據(jù)讀取問題;
解決了因加鎖導(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í)用的文章!
免責(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)容。