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