常言說得好,每一個成功男人背後都有一個爲他默默付出的女人,而對於MySQL來講,這個「人」就是InnoDB存儲引擎。數據庫
MySQL區別於其餘數據庫的最爲重要的特色就是其插件式的表存儲引擎。而在衆多存儲引擎中,InnoDB是最爲經常使用的存儲引擎。從MySQL5.5.8版本開始,InnoDB存儲引擎是默認的存儲引擎。緩存
InnoDB存儲引擎支持事務,其設計目標主要面向在線事務處理(OLTP)的應用。其特色是行鎖設計、支持外鍵,並支持非鎖定讀,即默認讀操做不會產生鎖。微信
InnoDB經過使用多版本併發控制(MVCC)來獲取高併發性,而且實現了SQL標準的4中隔離級別,默認爲REPEATABLE級別。同時,使用一種被稱爲next-key-locking的策略來避免幻讀現象的產生。除此以外,InnoDB存儲引擎還提供了插入緩衝(insert buffer)、二次寫(double write)、自適應哈希索引(adaptive hash index)、預讀(read ahead)等高性能和高可用的功能。架構
InnoDB存儲引擎是基於磁盤存儲的,並將其中的記錄按照頁的方式進行管理。可是因爲CPU速度和磁盤速度之間的鴻溝,基於磁盤的數據庫系統一般使用緩衝池記錄來提升數據庫的的總體性能。併發
在數據庫中進行讀取操做,首先將從磁盤中讀到的頁放在緩衝池中,下次再讀相同的頁中時,首先判斷該頁是否在緩衝池中。若在緩衝池中,稱該頁在緩衝池中被命中,直接讀取該頁。不然,讀取磁盤上的頁。函數
對於數據庫中頁的修改操做,則首先修改在緩衝池中的頁,而後再以必定的頻率刷新到磁盤上。頁從緩衝池刷新回磁盤的操做並非在每次頁發生更新時觸發,而是經過一種稱爲CheckPoint的機制刷新回磁盤。高併發
因此,緩衝池的大小直接影響着數據庫的總體性能,能夠經過配置參數innodb_buffer_pool_size來設置。性能
具體來看,緩衝池中緩存的數據頁類型有:索引頁、數據頁、undo頁、插入緩衝(insert buffer)、自適應哈希索引(adaptive hash index)、InnoDB存儲的鎖信息(lock info)和數據字典信息(data dictionary)。學習
在架構圖上能夠看到,InnoDB存儲引擎的內存區域除了有緩衝池以外,還有重作日誌緩衝和額外內存池。InnoDB存儲引擎首先將重作日誌信息先放到這個緩衝區中,而後按照必定頻率將其刷新到重作日誌文件中。重作日誌緩衝通常不須要設置的很大,該值可由配置參數innodb_log_buffer_size控制。優化
Page是Innodb存儲的最基本結構,也是Innodb磁盤管理的最小單位,與數據庫相關的全部內容都存儲在Page結構裏。Page分爲幾種類型,數據頁和索引頁就是其中最爲重要的兩種類型。
咱們都知道,在InnoDB引擎上進行插入操做時,通常須要按照主鍵順序進行插入,這樣才能得到較高的插入性能。當一張表中存在非聚簇的且不惟一的索引時,在插入時,數據頁的存放仍是按照主鍵進行順序存放,可是對於非聚簇索引葉節點的插入再也不是順序的了,這時就須要離散的訪問非聚簇索引頁,因爲隨機讀取的存在致使插入操做性能降低。
InnoDB爲此設計了Insert Buffer來進行插入優化。對於非聚簇索引的插入或者更新操做,不是每一次都直接插入到索引頁中,而是先判斷插入的非彙集索引是否在緩衝池中,若在,則直接插入;若不在,則先放入到一個Insert Buffer中。看似數據庫這個非彙集的索引已經查到葉節點,而實際沒有,這時存放在另一個位置。而後再以必定的頻率和狀況進行Insert Buffer和非聚簇索引頁子節點的合併操做。這時一般可以將多個插入合併到一個操做中,這樣就大大提升了對於非聚簇索引的插入性能。
若是說Insert Buffer給InnoDB存儲引擎帶來了性能上的提高,那麼Double Write帶給InnoDB存儲引擎的是數據頁的可靠性。
如上圖所示,Double Write由兩部分組成,一部分是內存中的double write buffer,大小爲2MB,另外一部分是物理磁盤上共享表空間連續的128個頁,大小也爲2MB。在對緩衝池的髒頁進行刷新時,並不直接寫磁盤,而是經過memcpy函數將髒頁先複製到內存中的該區域,以後經過doublewrite buffer再分兩次,每次1MB順序地寫入共享表空間的物理磁盤上,而後立刻調用fsync函數,同步磁盤,避免操做系統緩衝寫帶來的問題。在完成doublewrite頁的寫入後,再講doublewirite buffer中的頁寫入各個表空間文件中。
若是操做系統在將頁寫入磁盤的過程當中發生了崩潰,在恢復過程當中,InnoDB存儲引擎能夠從共享表空間中的doublewrite中找到該頁的一個副本,將其複製到表空間文件中,再應用重作日誌。
當緩衝池中的頁的版本比磁盤要新時,數據庫須要將新版本的頁從緩衝池刷新到磁盤。可是若是每次一個頁發送變化,就進行刷新,那麼性能開發是很是大的,因而InnoDB採用了Write Ahead Log策略,即當事務提交時,先寫重作日誌,而後再擇時將髒頁寫入磁盤。若是發生宕機致使數據丟失,就經過重作日誌進行數據恢復。
InnoDB存儲引擎會首先將重作日誌信息先放入重作日誌緩衝中,而後再按照必定頻率將其刷新到重作日誌文件。重作日誌緩衝通常不須要設置得很大,由於通常狀況每一秒鐘都會講重作日誌緩衝刷新到日誌文件中。可經過配置參數innodb_log_buffer_size控制,默認爲8MB。
除了每秒刷新機制以外,每次事務提交時重作日誌緩衝也會刷新到日誌中。InnoDB是事務的存儲引擎,其經過Force Log at Commit機制實現事務的持久性,即當事務提交時,必須先將該事務的全部日誌寫入到重作日誌文件進行持久化,而後事務的提交操做完成纔算完成。InnoDB的寫入機制大體入下圖所示。
爲了確保每第二天志都寫入到重作日誌文件,在每次講重作日誌緩衝寫入重作日誌後,必須調用一次fsync操做,將緩衝文件從文件系統緩存中真正寫入磁盤。
能夠經過innodb_flush_log_at_trx_commit來控制重作日誌刷新到磁盤的策略。該參數默認值爲1,表示事務提交必須進行一次fsync操做,還能夠設置爲0和2。0表示事務提交時不進行寫入重作日誌操做,該操做只在主線程中完成,2表示提交時寫入重作日誌,可是隻寫入文件系統緩存,不進行fsync操做。因而可知,設置爲0時,性能最高,可是喪失了事務的一致性。
InnoDB會根據訪問的頻率和模式,爲熱點頁創建哈希索引,來提升查詢效率。InnoDB存儲引擎會監控對錶上各個索引頁的查詢,若是觀察到創建哈希索引能夠帶來速度上的提高,則創建哈希索引,因此叫作自適應哈希索引。
自適應哈希索引是經過緩衝池的B+樹頁構建而來,所以創建速度很快,並且不須要對整張數據表創建哈希索引。其有一個要求,即對這個頁的連續訪問模式必須是同樣的,也就是說其查詢的條件(WHERE)必須徹底同樣,並且必須是連續的。
咱們都知道,InnoDB存儲引擎會在行級別上對錶數據進行上鎖。不過InnoDB也會在數據庫內部其餘不少地方使用鎖,從而容許對多種不一樣資源提供併發訪問。數據庫系統使用鎖是爲了支持對共享資源進行併發訪問,提供數據的完整性和一致性。關於鎖的具體知識咱們以後再進行詳細學習。
InnoDB有本身的表緩存,能夠稱爲表定義緩存或者數據字典。當InnoDB打開一張表,就增長一個對應的對象到數據字典。
數據字典是對數據庫中的數據、庫對象、表對象等的元信息的集合。在MySQL中,數據字典信息內容就包括表結構、數據庫名或表名、字段的數據類型、視圖、索引、表字段信息、存儲過程、觸發器等內容。MySQL INFORMATION_SCHEMA庫提供了對數據局元數據、統計信息、以及有關MySQL server的訪問信息(例如:數據庫名或表名,字段的數據類型和訪問權限等)。該庫中保存的信息也能夠稱爲MySQL的數據字典。
本篇文章只是簡單的介紹一下InnoDB內存相關的概念和原理,若是你們想要了解更多關於InnoDB的知識,請關注個人微信公衆號。