這篇文章給大家分享的是有關(guān)MySQL中InnoDB存儲(chǔ)引擎是什么的內(nèi)容。小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧。
創(chuàng)新互聯(lián)公司自2013年起,先為海口等服務(wù)建站,??诘鹊仄髽I(yè),進(jìn)行企業(yè)商務(wù)咨詢(xún)服務(wù)。為??谄髽I(yè)網(wǎng)站制作PC+手機(jī)+微官網(wǎng)三網(wǎng)同步一站式服務(wù)解決您的所有建站問(wèn)題。在MySQL中InnoDB屬于存儲(chǔ)引擎層,并以插件的形式集成在數(shù)據(jù)庫(kù)中。從MySQL5.5.8開(kāi)始,InnoDB成為其默認(rèn)的存儲(chǔ)引擎。InnoDB存儲(chǔ)引擎支持事務(wù)、其設(shè)計(jì)目標(biāo)主要是面向OLTP的應(yīng)用,主要特點(diǎn)有:支持事務(wù)、行鎖設(shè)計(jì)支持高并發(fā)、外鍵支持、自動(dòng)崩潰恢復(fù)、聚簇索引的方式組織表結(jié)構(gòu)等。
體系架構(gòu)
InnoDB存儲(chǔ)引擎是由內(nèi)存池、后臺(tái)線程、磁盤(pán)存儲(chǔ)三大部分組成。
線程
InnoDB 使用的是多線程模型, 其后臺(tái)有多個(gè)不同的線程負(fù)責(zé)處理不同的任務(wù)
Master Thread是最核心的一個(gè)后臺(tái)線程,主要負(fù)責(zé)將緩沖池中的數(shù)據(jù)異步刷新到磁盤(pán),保證數(shù)據(jù)的一致性。包括臟頁(yè)刷新、合并插入緩沖、UNDO頁(yè)的回收等。
在 InnoDB 存儲(chǔ)引擎中大量使用了異步IO(Async IO)來(lái)處理寫(xiě)IO請(qǐng)求, IO Thread的工作主要是負(fù)責(zé)這些 IO 請(qǐng)求的回調(diào)。
事務(wù)提交后,其所使用的undo log可能不再需要,因此需要Purge Thread來(lái)回收已經(jīng)分配并使用的UNDO頁(yè)。InnoDB支持多個(gè)Purge Thread, 這樣做可以加快UNDO頁(yè)的回收,提高CPU的使用率以及提升存儲(chǔ)引擎的性能。
Page Cleaner Thread的作用是取代Master Thread中臟頁(yè)刷新的操作,其目的是減輕原Master Thread的工作及對(duì)于用戶(hù)查詢(xún)線程的阻塞,進(jìn)一步提高InnoDB存儲(chǔ)引擎的性能。
內(nèi)存
InnoDB 存儲(chǔ)引擎內(nèi)存的結(jié)構(gòu)
InnoDB存儲(chǔ)引擎是基于磁盤(pán)存儲(chǔ)的,并將其中的記錄按照頁(yè)的方式進(jìn)行管理。但是由于CPU速度和磁盤(pán)速度之間的鴻溝,基于磁盤(pán)的數(shù)據(jù)庫(kù)系統(tǒng)通常使用緩沖池記錄來(lái)提高數(shù)據(jù)庫(kù)的的整體性能。
緩沖池其實(shí)就是通過(guò)內(nèi)存的速度來(lái)彌補(bǔ)磁盤(pán)速度較慢對(duì)數(shù)據(jù)庫(kù)性能的影響。在數(shù)據(jù)庫(kù)進(jìn)行讀取操作時(shí),首先將磁盤(pán)中的頁(yè)放入緩沖池中,下次再讀取相同頁(yè)時(shí),首先從緩沖池中獲取該頁(yè)數(shù)據(jù),起到高速緩存的作用。
數(shù)據(jù)的修改操作,則首先修改在緩沖池中的頁(yè)數(shù)據(jù),然后使用一種稱(chēng)為Checkpoint的機(jī)制刷新到磁盤(pán)上。
緩沖池的大小直接影響數(shù)據(jù)庫(kù)的整體性能,對(duì)于InnoDB存儲(chǔ)引擎而言,緩沖池配置通過(guò)參數(shù) innodb_buffer_pool_size 來(lái)設(shè)置。使用 SHOW VARIABLES LIKE 'innodb_buffer_pool_size'
命令可查看緩沖池配置:
mysql> SHOW VARIABLES LIKE 'innodb_buffer_pool_size' \G *************************** 1. row *************************** Variable_name: innodb_buffer_pool_size Value: 134217728 1 row in set (0.01 sec)
緩沖池中緩存的數(shù)據(jù)頁(yè)類(lèi)型有: 索引頁(yè)、undo頁(yè)、插入緩沖、自適應(yīng)哈希索引、InnoDB鎖信息、數(shù)據(jù)字典信息等,索引頁(yè)和數(shù)據(jù)頁(yè)占緩沖池很大的一部分。
緩沖池中的頁(yè)數(shù)據(jù)比磁盤(pán)要新時(shí),需要將新數(shù)據(jù)刷新到磁盤(pán)中。InnoDB采用Write Ahead Log策略來(lái)刷新數(shù)據(jù),即當(dāng)事務(wù)提交時(shí),先寫(xiě)入重做日志緩沖,重做日志緩沖會(huì)按一定頻率刷新到重置日志文件中,然后臟頁(yè)會(huì)根據(jù)checkpoint機(jī)制刷新到磁盤(pán)。
重做日志緩沖不需要設(shè)置很大,通常情況下8M能滿(mǎn)足大部分的應(yīng)用場(chǎng)景。重做日志支持一下三種情況觸發(fā)刷新:
Master Thread每一秒將重做日志緩沖刷新到重做日志文件
每次事務(wù)提交時(shí)將重做日志緩沖刷新到重做日志文件
當(dāng)重做日志緩沖池剩余空間小于1/2時(shí),重做日志緩沖刷新到重做日志文件
在InnoDB存儲(chǔ)引擎中,對(duì)內(nèi)存的管理是通過(guò)一種稱(chēng)為內(nèi)存堆的方式進(jìn)行的。在對(duì)一些數(shù)據(jù)結(jié)構(gòu)本身的內(nèi)存進(jìn)行分配時(shí),需要從額外的內(nèi)存池中進(jìn)行申請(qǐng),當(dāng)該區(qū)域的內(nèi)存不夠時(shí),會(huì)從緩沖池中進(jìn)行申請(qǐng)。
鎖
InnoDB支持的鎖有:
共享鎖和排它鎖
意向鎖
記錄鎖
間隙鎖
自增鎖
InnoDB引擎實(shí)現(xiàn)了兩種標(biāo)準(zhǔn)的行級(jí)鎖,共享鎖(shared (S) locks) 和排他鎖 (exclusive (X) locks)。共享鎖允許一個(gè)占有鎖的事務(wù)去讀取一行數(shù)據(jù),排它鎖則允許事務(wù)對(duì)某一行記錄進(jìn)行寫(xiě)操作。
如果一個(gè)事務(wù)持有了一個(gè)共享鎖,其他事務(wù)仍然可以獲取這行記錄的共享鎖,但不能獲取到這行記錄的排它鎖。當(dāng)一個(gè)事務(wù)獲取到了某一行的排它鎖,則其他事務(wù)將無(wú)法再獲取這行記錄的共享鎖和排它鎖。
在InnoDB中,意向鎖是一種表級(jí)鎖,分為共享鎖和排他鎖:
意向共享鎖:將要去獲取某一行的共享鎖
意向排它鎖:將要去獲取某一行的排它鎖
事務(wù)在獲取共享/排它鎖之前必須先獲取意向共享/排它鎖,意向鎖不會(huì)阻塞其他任何對(duì)表的操作,他只是告訴其他事務(wù)他將要去獲取某一行的共享鎖或者排他鎖。
記錄是是作用在索引上的一種鎖,他鎖住的是某一條記錄的索引而非記錄本身,如果當(dāng)前表沒(méi)有索引那么InnoDB將會(huì)為其創(chuàng)建一個(gè)隱藏的聚集索引,而Record Locks將會(huì)鎖住這個(gè)隱藏的聚集索引。
間隙鎖和記錄鎖一樣也是作用在索引上,不同的是記錄鎖只作用于一條索引記錄而間隙鎖可以鎖住一個(gè)范圍內(nèi)的索引。間隙鎖在InnoDB的唯一作用就是防止其他事務(wù)的插入操作,以此防止幻讀的發(fā)生。
自增鎖是一種特殊的表級(jí)鎖,他只作用在包含自增列的插入操作時(shí)。當(dāng)一個(gè)事務(wù)正在插入一條數(shù)據(jù)時(shí),其他的任何事務(wù)都必須等待整個(gè)事務(wù)完成插入操作,在取獲取鎖來(lái)執(zhí)行插入操作。
事務(wù)
ACID
事務(wù)是數(shù)據(jù)庫(kù)作為OLTP最為重要的特性,說(shuō)起事務(wù)不得不提起ACID四個(gè)基本特性:
原子性(Atomicity) :事務(wù)最小工作單元,要么全成功,要么全失敗
一致性(Consistency): 事務(wù)開(kāi)始和結(jié)束后,數(shù)據(jù)庫(kù)的完整性不會(huì)被破壞
隔離性(Isolation) :不同事務(wù)之間互不影響,四種隔離級(jí)別為RU(讀未提交)、RC(讀已提交)、RR(可重復(fù)讀)、SERIALIZABLE (串行化)
持久性(Durability) :事務(wù)提交后,對(duì)數(shù)據(jù)的修改是永久性的,即使系統(tǒng)故障也不會(huì)丟失
InnoDB的原子性、持久性和一致性主要是通過(guò)Redo Log、Undo Log和Force Log at Commit機(jī)制機(jī)制來(lái)完成的。Redo Log用于在崩潰時(shí)恢復(fù)數(shù)據(jù),Undo Log用于對(duì)事務(wù)的影響進(jìn)行撤銷(xiāo),也可以用于多版本控制。而Force Log at Commit機(jī)制保證事務(wù)提交后Redo Log日志都已經(jīng)持久化。隔離性則是由鎖和MVCC來(lái)保證的。
在MySQL中,事務(wù)有4種隔離級(jí)別,分別是:
Read Uncommitted 未提交讀
Read Committed 已提交讀
Repeatable Read 可重復(fù)讀
Serializable 可串行化
在理解四種隔離級(jí)別之前,我們需要先了解另外三個(gè)名詞:
臟讀
a事務(wù)會(huì)讀取到b事務(wù)還未提交的數(shù)據(jù),但是b事務(wù)由于某種原因進(jìn)行回滾操作,這樣,a事務(wù)讀取的數(shù)據(jù)是不可用的,進(jìn)而會(huì)造成一些異常結(jié)果。
不可重復(fù)讀
a事務(wù)周期內(nèi)對(duì)某一數(shù)據(jù)多次查詢(xún),同時(shí)這些數(shù)據(jù)在b事務(wù)中進(jìn)行了update或delete操作。那么a事務(wù)每次查詢(xún)出來(lái)的結(jié)果可能都不一樣。
幻讀
幻讀的結(jié)果其實(shí)和不可重復(fù)讀是一樣的表現(xiàn),差異就在于不可重復(fù)讀主要是針對(duì)其他事務(wù)進(jìn)行了編輯(update)和刪除(delete)操作。而幻讀主要是針對(duì)插入(insert)操作。也就是在一個(gè)事務(wù)生命周期內(nèi),會(huì)查詢(xún)到另外一個(gè)事務(wù)新插入的數(shù)據(jù)。
未提交讀,這種情況下,一個(gè)事務(wù)a可以看到另一個(gè)事務(wù)b未提交的數(shù)據(jù),如果此時(shí)事務(wù)b發(fā)生回滾,那么事務(wù)a拿到的就是臟數(shù)據(jù),這也就是臟讀的含義。
此隔離級(jí)別在MySQL InnoDB一般不推薦使用。
已提交讀,一個(gè)事務(wù)從開(kāi)始直到提交之前,所做的任何修改對(duì)其他事務(wù)都是不可見(jiàn)的。解決了臟讀問(wèn)題,但是存在幻讀現(xiàn)象。
可重復(fù)讀,該級(jí)別保證在同一事務(wù)中多次讀取同樣記錄的結(jié)果是一致的,在InnoDB存儲(chǔ)引擎中同時(shí)解決了幻讀和不可重復(fù)讀問(wèn)題。
InnoDB引擎通過(guò)使用Next-Key Lock
解決了幻讀的問(wèn)題。Next-Key Lock
是行鎖和間隙鎖的組合,當(dāng)InnoDB掃描索引記錄的時(shí)候,會(huì)首先對(duì)索引記錄加上行鎖(Record Lock),再對(duì)索引記錄兩邊的間隙加上間隙鎖(Gap Lock)。加上間隙鎖之后,其他事務(wù)就不能在這個(gè)間隙修改或者插入記錄。
Serializable 是最高的隔離級(jí)別,它通過(guò)強(qiáng)制事務(wù)串行執(zhí)行,避免了幻讀的問(wèn)題,但是 Serializable 會(huì)在讀取的每一行數(shù)據(jù)上都加鎖,所以可能導(dǎo)致大量的超時(shí)和鎖爭(zhēng)用的問(wèn)題,因此并發(fā)度急劇下降,在MySQL InnoDB同樣不被建議使用。
BEGIN、BEGIN WORK、START TRANSACTION
執(zhí)行BEGIN命令不會(huì)真正在引擎層開(kāi)啟新事務(wù),僅僅是為當(dāng)前線程設(shè)定標(biāo)記,表示為顯式開(kāi)啟的事務(wù)。
START TRANSACTION READ ONLY
開(kāi)啟只讀事務(wù),當(dāng)MySQL Server接收到任何數(shù)據(jù)更改的SQL時(shí),都會(huì)直接拒絕修改并返回錯(cuò)誤,此錯(cuò)我不會(huì)進(jìn)入引擎層。
START TRANSACTION READ WRITE
允許super用戶(hù)在當(dāng)前線程只讀狀態(tài)為true的情況下啟動(dòng)讀寫(xiě)事務(wù)。
START TRANSACTION WITH CONSISTENT SNAPSHOT
開(kāi)啟事務(wù)會(huì)進(jìn)入引擎層,并開(kāi)啟一個(gè)readview
。只有在RR隔離級(jí)別下,這種操作才有效,否則會(huì)報(bào)錯(cuò)。
在數(shù)據(jù)進(jìn)行修改時(shí)會(huì)記錄相應(yīng)的undo日志,如果事務(wù)失敗或者回滾,可以借助記錄的undo日志進(jìn)行回滾。Undo log是邏輯日志,記錄更改前的數(shù)據(jù)鏡像。在修改時(shí)如果同時(shí)需要讀取當(dāng)前數(shù)據(jù)的時(shí)候,它可以根據(jù)版本信息分析出該行記錄以前版本的數(shù)據(jù)。另外Undo log也會(huì)產(chǎn)生重做日志,因?yàn)閁ndo log也要進(jìn)行持久化保護(hù)。
使用全局事務(wù)ID產(chǎn)生器生成事務(wù)NO,將當(dāng)前連接的事務(wù)指針(trx_t
)添加到全局提交事務(wù)鏈表(trx_serial_list
)中
標(biāo)記undo,如果這個(gè)事務(wù)只使用了一個(gè)UndoPage且使用量小于3/4個(gè)Page,則把這個(gè)Page標(biāo)記為TRX_UNDO_CACHED
,如果不滿(mǎn)足且是insert undo
則標(biāo)記為TRX_UNDO_TO_FREE
,否則undo為update undo則標(biāo)記為TRX_UNDO_TO_PURGE
。標(biāo)記為TRX_UNDO_CACHED
的undo會(huì)被引擎回收。
把update undo
放入所在undo segment
的history list
,并遞增rseg_history_len
(全局)。同時(shí)更新Page上的TRX_UNDO_TRX_NO
, 如果刪除了數(shù)據(jù),則重置delete_mark
把undate undo
從update_undo_list
中刪除,如果被標(biāo)記為TRX_UNDO_CACHED
,則加入到update_undo_cached
隊(duì)列中
mtr_commit
(日志undo/redo寫(xiě)入公共緩沖區(qū)),至此,在文件層次事務(wù)提交。這個(gè)時(shí)候即使crash,重啟后依然能保證事務(wù)是被提交的。接下來(lái)要做的是內(nèi)存數(shù)據(jù)狀態(tài)的更新(trx_commit_in_memory
)
只讀事務(wù)只需要把readview
從全局readview
鏈表中移除,然后重置trx_t
結(jié)構(gòu)體里面的信息即可。讀寫(xiě)事務(wù)首先需要是設(shè)置事務(wù)狀態(tài)為TRX_STATE_COMMITTED_IN_MEMORY
,釋放所有行鎖并且將trx_t
從rw_trx_list
中移除,readview
從全局readview
鏈表中移除。如果有insert undo
則在這里移除,如果有update undo
則喚醒Purge線程進(jìn)行垃圾清理,最后重置trx_t
里的信息,便于下一個(gè)事務(wù)使用
如果是只讀事務(wù),則直接返回
判斷當(dāng)前是回滾整個(gè)事務(wù)還是部分事務(wù),如果是部分事務(wù),則記錄下需要保留多少個(gè)Undo log,多余的全進(jìn)行回滾
從update undo
和insert undo
中找出最后一條undo,從這條undo開(kāi)始回滾
如果是update undo
則將標(biāo)記為刪除的記錄清理標(biāo)記,更新過(guò)的數(shù)據(jù)回滾到最老的版本。如果是insert undo
則直接刪除聚集索引和二級(jí)索引
如果所有undo都已經(jīng)被回滾或者回滾到了指定的undo則停止,把Undo log刪除
索引
InnoDB引擎使用B+樹(shù)作為索引結(jié)構(gòu),主鍵索引的葉子節(jié)點(diǎn)data域保存了完整的字段數(shù)據(jù),非主鍵索引的葉子節(jié)點(diǎn)保存了指向主鍵的值數(shù)據(jù)。
上圖是 InnoDB 主索引(同時(shí)也是數(shù)據(jù)文件)的示意圖,可以看到葉節(jié)點(diǎn)包含了完整的數(shù)據(jù)記錄,這種索引叫做聚集索引。因?yàn)?InnoDB 的數(shù)據(jù)文件本身要按主鍵聚集,所以 InnoDB 要求表必須有主鍵,如果沒(méi)有顯式指定,則 MySQL 系統(tǒng)會(huì)自動(dòng)選擇一個(gè)可以唯一標(biāo)識(shí)數(shù)據(jù)記錄的列作為主鍵,如果不存在這種列,則 MySQL 自動(dòng)為 InnoDB 表生成一個(gè)隱含字段作為主鍵,這個(gè)字段長(zhǎng)度為6個(gè)字節(jié),類(lèi)型為長(zhǎng)整形。
InnoDB 的輔助索引 data 域存儲(chǔ)相應(yīng)記錄主鍵的值而不是地址。換句話說(shuō),InnoDB 的所有輔助索引都引用主鍵作為 data 域。聚集索引這種實(shí)現(xiàn)方式使得按主鍵的搜索十分高效,但是輔助索引搜索需要檢索兩遍索引:首先檢索輔助索引獲得主鍵,然后用主鍵到主索引中檢索獲得記錄。
感謝各位的閱讀!關(guān)于MySQL中InnoDB存儲(chǔ)引擎是什么就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,讓大家可以學(xué)到更多知識(shí)。如果覺(jué)得文章不錯(cuò),可以把它分享出去讓更多的人看到吧!
另外有需要云服務(wù)器可以了解下創(chuàng)新互聯(lián)scvps.cn,海內(nèi)外云服務(wù)器15元起步,三天無(wú)理由+7*72小時(shí)售后在線,公司持有idc許可證,提供“云服務(wù)器、裸金屬服務(wù)器、高防服務(wù)器、香港服務(wù)器、美國(guó)服務(wù)器、虛擬主機(jī)、免備案服務(wù)器”等云主機(jī)租用服務(wù)以及企業(yè)上云的綜合解決方案,具有“安全穩(wěn)定、簡(jiǎn)單易用、服務(wù)可用性高、性?xún)r(jià)比高”等特點(diǎn)與優(yōu)勢(shì),專(zhuān)為企業(yè)上云打造定制,能夠滿(mǎn)足用戶(hù)豐富、多元化的應(yīng)用場(chǎng)景需求。