HOME 首頁(yè)
SERVICE 服務(wù)產(chǎn)品
XINMEITI 新媒體代運(yùn)營(yíng)
CASE 服務(wù)案例
NEWS 熱點(diǎn)資訊
ABOUT 關(guān)于我們
CONTACT 聯(lián)系我們
創(chuàng)意嶺
讓品牌有溫度、有情感
專注品牌策劃15年

    mysql快照讀(mysql快照讀原理)

    發(fā)布時(shí)間:2023-04-08 06:12:51     稿源: 創(chuàng)意嶺    閱讀: 73        

    大家好!今天讓創(chuàng)意嶺的小編來(lái)大家介紹下關(guān)于mysql快照讀的問(wèn)題,以下是小編對(duì)此問(wèn)題的歸納整理,讓我們一起來(lái)看看吧。

    開始之前先推薦一個(gè)非常厲害的Ai人工智能工具,一鍵生成原創(chuàng)文章、方案、文案、工作計(jì)劃、工作報(bào)告、論文、代碼、作文、做題和對(duì)話答疑等等

    只需要輸入關(guān)鍵詞,就能返回你想要的內(nèi)容,越精準(zhǔn),寫出的就越詳細(xì),有微信小程序端、在線網(wǎng)頁(yè)版、PC客戶端

    官網(wǎng):https://ai.de1919.com

    創(chuàng)意嶺作為行業(yè)內(nèi)優(yōu)秀的企業(yè),服務(wù)客戶遍布全球各地,如需了解SEO相關(guān)業(yè)務(wù)請(qǐng)撥打電話175-8598-2043,或添加微信:1454722008

    本文目錄:

    mysql快照讀(mysql快照讀原理)

    一、mysql是如何實(shí)現(xiàn)可重復(fù)讀的?

    一個(gè)事務(wù)要更新一行,如果剛好有另外一個(gè)事務(wù)擁有這一行的行鎖,會(huì)被鎖住,進(jìn)入等待狀態(tài)。既然進(jìn)入了等待狀態(tài),那么等到這個(gè)事務(wù)自己獲取到行鎖要更新數(shù)據(jù)的時(shí)候,它讀到的值又是什么呢?

    可重復(fù)讀隔離級(jí)別下,事務(wù)在啟動(dòng)的時(shí)候就“拍了個(gè)整個(gè)庫(kù)的快照”。如果一個(gè)庫(kù)有100G,那么我啟動(dòng)一個(gè)事務(wù),MySQL就要拷⻉100G的數(shù)據(jù)出來(lái),這個(gè)過(guò)程得多慢啊。但是平時(shí)事務(wù)執(zhí)行起來(lái)卻是非??斓?。不是全部拷貝出來(lái)那是怎么實(shí)現(xiàn)的呢?

    InnoDB里面每個(gè)事務(wù)有一個(gè)唯一的事務(wù)ID,叫作transaction id。它是在事務(wù)開始的時(shí)候向InnoDB的事務(wù)系統(tǒng)申請(qǐng)的,是按申請(qǐng)順序嚴(yán)格遞增的。

    而每行數(shù)據(jù)也都是有多個(gè)版本的。每次事務(wù)更新數(shù)據(jù)的時(shí)候,都會(huì)生成一個(gè)新的數(shù)據(jù)版本,并且把transaction id賦值給這個(gè)數(shù) 據(jù)版本的事務(wù)ID,記為row trx_id。同時(shí),舊的數(shù)據(jù)版本要保留,并且在新的數(shù)據(jù)版本中,能夠有信息可以直接拿到它。

    數(shù)據(jù)表中的一行記錄,其實(shí)可能有多個(gè)版本(row),每個(gè)版本有自己的row trx_id。

    圖中虛線框里是同一行數(shù)據(jù)的4個(gè)版本,當(dāng)前最新版本是V4,k的值是22,它是被transaction id 為25的事務(wù)更新的,因此它的row trx_id也是25。語(yǔ)句更新會(huì)生成undo log(回滾日志),圖中的三個(gè)虛線箭頭,就是undo log。

    按照可重復(fù)讀的定義,一個(gè)事務(wù)啟動(dòng)的時(shí)候,能夠看到所有已經(jīng)提交的事務(wù)結(jié)果。但是之后,這個(gè)事務(wù)執(zhí)行期間,其他事務(wù)的更新對(duì)它不可⻅。

    一個(gè)事務(wù)只需要在啟動(dòng)的時(shí)候聲明說(shuō),“以我啟動(dòng)的時(shí)刻為準(zhǔn),如果一個(gè)數(shù)據(jù)版本是在我啟動(dòng)之前生成的,就認(rèn);如果是我啟動(dòng)以后才生成的,我就不認(rèn),我必須要找到它的上一個(gè)版本”。

    如果“上一個(gè)版本”也不可⻅,那就得繼續(xù)往前找。如果是這個(gè)事務(wù)自己更新的數(shù)據(jù),它自己還是要認(rèn)的。

    在實(shí)現(xiàn)上, InnoDB為每個(gè)事務(wù)構(gòu)造了一個(gè)數(shù)組,用來(lái)保存這個(gè)事務(wù)啟動(dòng)瞬間,當(dāng)前正在“活躍”的所有事務(wù)ID?!盎钴S”指的就 是,啟動(dòng)了但還沒(méi)提交。數(shù)組里面事務(wù)ID的最小值記為低水位,當(dāng)前系統(tǒng)里面已經(jīng)創(chuàng)建過(guò)的事務(wù)ID的最大值加1記為高水位。 這個(gè)視圖數(shù)組和高水位,就組成了當(dāng)前事務(wù)的一致性視圖(read-view)。而數(shù)據(jù)版本的可⻅性規(guī)則,就是基于數(shù)據(jù)的row trx_id和這個(gè)一致性視圖的對(duì)比結(jié)果得到的。

    InnoDB利用了“所有數(shù)據(jù)都有多個(gè)版本”的這個(gè)特性,實(shí)現(xiàn)了“秒級(jí)創(chuàng)建快照”的能力。

    回到我們最開始的表格,看看最后執(zhí)行的結(jié)果是多少。做如下假設(shè):

    事務(wù)A的視圖數(shù)組就是[99,100], 事務(wù)B的視圖數(shù)組是[99,100,101], 事務(wù)C的視圖數(shù)組是[99,100,101,102]。為了簡(jiǎn)化分析,我先把其他干擾語(yǔ)句去掉,只畫出跟事務(wù)A查詢邏輯有關(guān)的操作:

    第一個(gè)有效更新是事務(wù)C,把數(shù)據(jù)從(1,1)改成了(1,2)。這時(shí)候,這個(gè)數(shù)據(jù)的最新版本的row trx_id是102,而90這個(gè)版本已經(jīng)成為了歷史版本。 第二個(gè)有效更新是事務(wù)B,把數(shù)據(jù)從(1,2)改成了(1,3)。這時(shí)候,這個(gè)數(shù)據(jù)的最新版本(即row trx_id)是101,而102又成為了歷史版本。

    事務(wù)B的update語(yǔ)句,如果按照一致性讀,好像結(jié)果不對(duì)哦?

    事務(wù)B的視圖數(shù)組是先生成的,之后事務(wù)C才提交,不是應(yīng)該看不⻅(1,2)嗎,怎么能算出(1,3)來(lái)?

    事務(wù)B在更新之前查詢一次數(shù)據(jù),這個(gè)查詢返回的k的值確實(shí)是1。 但是,當(dāng)它要去更新數(shù)據(jù)的時(shí)候,就不能再在歷史版本上更新了,否則事務(wù)C的更新就丟失了。因此,事務(wù)B此時(shí)的set k=k+1是在(1,2)的基礎(chǔ)上進(jìn)行的操作。 所以,這里就用到了這樣一條規(guī)則:更新數(shù)據(jù)都是先讀后寫的,而這個(gè)讀,只能讀當(dāng)前的值,稱為 “當(dāng)前讀” ( current read )。

    在更新的時(shí)候,當(dāng)前讀拿到的數(shù)據(jù)是(1,2),更新后生成了新版本的數(shù)據(jù)(1,3),這個(gè)新版本的row trx_id是101。

    所以,在執(zhí)行事務(wù)B查詢語(yǔ)句的時(shí)候,一看自己的版本號(hào)是101,最新數(shù)據(jù)的版本號(hào)也是101,是自己的更新,可以直接使用, 所以查詢得到的k的值是3。

    select語(yǔ)句如果加鎖,也是當(dāng)前讀。

    如果把事務(wù)A的查詢語(yǔ)句select * from t where id=1修改一下,加上lock in share mode 或 for update,也都可以讀到版本號(hào)是101的數(shù)據(jù),返回的k的值是3。下面這兩個(gè)select語(yǔ)句,就是分別加了讀鎖(S鎖,共享鎖)和寫鎖(X鎖,排他鎖)。

    事務(wù)C’的不同是,更新后并沒(méi)有⻢上提交,在它提交前,事務(wù)B的更新語(yǔ)句先發(fā)起了。前面說(shuō)過(guò)了,雖然事務(wù)C’還沒(méi)提交,但是(1,2)這個(gè)版本也已經(jīng)生成了,并且是當(dāng)前的最新版本。那么,事務(wù)B的更新語(yǔ)句會(huì)怎么處理呢?

    兩階段鎖協(xié)議,事務(wù)C’沒(méi)提交,也就是說(shuō)(1,2)這個(gè)版本上的寫鎖還沒(méi)釋放。 而事務(wù)B是當(dāng)前讀,必須要讀最新版本,而且必須加鎖,因此就被鎖住了,必須等到事務(wù)C’釋放這個(gè)鎖,才能繼續(xù)它的當(dāng)前讀。

    回到最初的問(wèn)題,事務(wù)的可重復(fù)讀的能力是怎么實(shí)現(xiàn)的?

    二、「MySQL」這個(gè)詞怎么讀?

    My S-Q-L,不專業(yè)的可以讀作 my sequel(???,但絕非是 賣塞科兒

    mysql快照讀(mysql快照讀原理)

    其實(shí)很多老師并不知道他的讀法,當(dāng)時(shí)聯(lián)系的數(shù)據(jù)庫(kù)是dbase, foxbase, foxpro, access, MS SQL server (oracle), 15年前,mysql類似于幼兒園的游戲。此外,SQL server還被用于遵從SQL 92.99標(biāo)準(zhǔn),在這方面mysql不太正式,因此您可以看到事務(wù)隔離級(jí)別。這樣也很不錯(cuò),mysql有很多非正式的,但更為方便的語(yǔ)法。

    具體可以看他的專業(yè)書。

    mysql快照讀(mysql快照讀原理)

    MySQL包含許多特性,特別是在MySQL 5.0和5.1中,添加了一些主要特性和特性。MySQL的特定功能或語(yǔ)句非常豐富。這就是為什么MySQL核心技術(shù)手冊(cè)(版本2)是有價(jià)值的?!癕ySQL核心技術(shù)手冊(cè)(第二版)”“需要讓讀者快速找到具體的細(xì)節(jié),無(wú)論是SQL關(guān)鍵字還是MySQL命令行選項(xiàng),特定的API信息或?qū)嵱贸绦蚬芾怼?/p>

    《“MySQL核心技術(shù)手冊(cè)(第二版)”“覆蓋適用于所有命令和MySQL 5.1版本的編程信息,包括一些新特性和語(yǔ)言界面,對(duì)于大多數(shù)語(yǔ)句和函數(shù),使用示例給出。

    mysql快照讀(mysql快照讀原理)

    MySQL核心技術(shù)手冊(cè)(版本2)為MySQL語(yǔ)句、函數(shù)、配置選項(xiàng)和實(shí)用程序提供了完整的手冊(cè)。為了幫助初學(xué)者入門,我們提供了一些教程。為PHP、Perl和C語(yǔ)言提供了應(yīng)用程序編程接口(api)。在每個(gè)章節(jié)的API開頭提供了一個(gè)簡(jiǎn)要的指南。新副本、觸發(fā)器和存儲(chǔ)過(guò)程部分。提供了一些MySQL的實(shí)際示例。一些有用的技巧可以幫助讀者克服困難。

    三、如何優(yōu)化因 MYSQL 讀寫頻繁,負(fù)載過(guò)高導(dǎo)致的CPU高占用率

    診斷思路

    mpstat -P ALL 1,查看cpu使用情況,主要消耗在sys即os系統(tǒng)調(diào)用上

    mysql快照讀(mysql快照讀原理)

    perf top,cpu主要消耗在_spin_lock

    mysql快照讀(mysql快照讀原理)

    生成perf report查看詳細(xì)情況

    mysql快照讀(mysql快照讀原理)

    CPU主要消耗在mutex爭(zhēng)用上,說(shuō)明有鎖熱點(diǎn)。

    采用pt-pmp跟蹤mysqld執(zhí)行情況,熱點(diǎn)主要集中在mem_heap_alloc和mem_heap_free上。

    mysql快照讀(mysql快照讀原理)

    Pstack提供更詳細(xì)的API調(diào)用棧

    Innodb在讀取數(shù)據(jù)記錄時(shí)的API路徑為

    row_search_for_mysql --》row_vers_build_for_consistent_read --》mem_heap_create_block_func --》mem_area_alloc --》malloc --》  _L_unlock_10151 --》__lll_unlock_wait_private

    row_vers_build_for_consistent_read會(huì)陷入一個(gè)死循環(huán),跳出條件是該條記錄不需要快照讀或者已經(jīng)從undo中找出對(duì)應(yīng)的快照版本,每次循環(huán)都會(huì)調(diào)用mem_heap_alloc/free。

    而該表的記錄更改很頻繁,導(dǎo)致其undo history list比較長(zhǎng),搜索快照版本的代價(jià)更大,就會(huì)頻繁的申請(qǐng)和釋放堆內(nèi)存。

    Linux原生的內(nèi)存庫(kù)函數(shù)為ptmalloc,malloc/free調(diào)用過(guò)多時(shí)很容易產(chǎn)生鎖熱點(diǎn)。

    當(dāng)多條 SQL 并發(fā)執(zhí)行時(shí),會(huì)最終觸發(fā)os層面的spinlock,導(dǎo)致上述情形。

    解決方案

    將mysqld的內(nèi)存庫(kù)函數(shù)替換成tcmalloc,相比ptmalloc,tcmalloc可以更好的支持高并發(fā)調(diào)用。

    修改my.cnf,添加如下參數(shù)并重啟

    [mysqld_safe]malloc-lib=tcmalloc

    上周五早上7點(diǎn)執(zhí)行的操作,到現(xiàn)在超過(guò)72小時(shí),期間該實(shí)例沒(méi)有再出現(xiàn)cpu長(zhǎng)期飆高的情形。

    以下是修改前后cpu使用率對(duì)比

    mysql快照讀(mysql快照讀原理)

    四、mysql在RR隔離級(jí)別下,某些特定場(chǎng)景下出現(xiàn)幻讀

    見圖,主要是select xx for update,又或者是update語(yǔ)句更新了,使用了當(dāng)前讀。所以后面再次select(13行)出現(xiàn)幻讀,如果只是select的話(10行不是update,是個(gè)select),是不會(huì)出現(xiàn)幻讀的情況,因?yàn)榉蟤vcc規(guī)則,用的還是一開始的快照。

    todo:看下10行是update的情況下的內(nèi)容:SELECT * FROM information_schema . INNODB_TRX

    如果10行,update的id為1,則不會(huì)出現(xiàn)幻讀的情況,這里因?yàn)閡pdate的時(shí)候把session2里的更新到了

    以上就是關(guān)于mysql快照讀相關(guān)問(wèn)題的回答。希望能幫到你,如有更多相關(guān)問(wèn)題,您也可以聯(lián)系我們的客服進(jìn)行咨詢,客服也會(huì)為您講解更多精彩的知識(shí)和內(nèi)容。


    推薦閱讀:

    academy諧音記憶

    vin碼黑色的牌在車的什么位置上(my黑色車牌)

    歷史看過(guò)的網(wǎng)站(歷史看過(guò)的網(wǎng)站mY)

    怎么把word放到右鍵新建(怎么把word放到右鍵新建頁(yè)面)

    淘寶店鋪轉(zhuǎn)讓價(jià)格表2022(2鉆淘寶店鋪轉(zhuǎn)讓價(jià)格表)