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