世界上最快的捷徑,就是腳踏實地,本文已收錄【架構技術專欄】關注這個喜歡分享的地方。數據庫
InnoDB引擎有幾個重點特性,爲其帶來了更好的性能和可靠性:數據結構
今天咱們的主題就是 插入緩衝(Insert Buffer)
,因爲InnoDB引擎底層數據存儲結構式B+樹,而對於索引咱們又有彙集索引和非彙集索引。架構
在進行數據插入時必然會引發索引的變化,彙集索引沒必要說,通常都是遞增有序的。而非彙集索引就不必定是什麼數據了,其離散性致使了在插入時結構的不斷變化,從而致使插入性能下降。異步
因此爲了解決非彙集索引插入性能的問題,InnoDB引擎 創造了Insert Buffer。性能
看到上圖,可能你們會認爲Insert Buffer 就是InnoDB 緩衝池的一個組成部分。優化
重點:其實對也不對,InnoDB 緩衝池確實包含了Insert Buffer的信息,但Insert Buffer 其實和數據頁同樣,也是物理存在的(以B+樹的形式存在共享表空間中)。線程
先說幾個點:設計
一張表只能有一個主鍵索引,那是由於其物理存儲是一個B+樹。(別忘了彙集索引葉子節點存儲的數據,而數據只有一份)code
非彙集索引葉子節點存的是彙集索引的主鍵對象
首先咱們知道在InnoDB存儲引擎中,主鍵是行惟一的標識符(也就是咱們常叨叨的彙集索引)。咱們平時插入數據通常都是按照主鍵遞增插入,所以彙集索引都是順序的,不須要磁盤的隨機讀取。
好比表:
CREATE TABLE test( id INT AUTO_INCREMENT, name VARCHAR(30), PRIMARY KEY(id) );
如上我建立了一個主鍵 id,它有如下的特性:
通常狀況下因爲彙集索引的有序性,不須要隨機讀取頁中的數據,由於此類的順序插入速度是很是快的。
但若是你把列 Id 插入UUID這種數據,那你插入就是和非彙集索引同樣都是隨機的了。會致使你的B+ tree結構不停地變化,那性能必然會受到影響。
不少時候咱們的表還會有不少非彙集索引,好比我按照b字段查詢,且b字段不是惟一的。以下表:
CREATE TABLE test( id INT AUTO_INCREMENT, name VARCHAR(30), PRIMARY KEY(id), KEY(name) );
這裏我建立了一個x表,它有如下特色:
非彙集索引也是一顆B+樹,只是葉子節點存的是彙集索引的主鍵和name 的值。
由於不能保證name列的數據是順序的,因此非彙集索引這棵樹的插入必然也不是順序的了。
固然若是name列插入的是時間類型數據,那其非彙集索引的插入也是順序的。
能夠看出非彙集索引插入的離散性致使了插入性能的降低,所以InnoDB引擎設計了 Insert Buffer來提升插入性能 。
我來看看使用Insert Buffer 是怎麼插入的:
首先對於非彙集索引的插入或更新操做,不是每一次直接插入到索引頁中,而是先判斷插入的非彙集索引頁是否在緩衝池中。
若在,則直接插入;若不在,則先放入到一個Insert Buffer對象中。
給外部的感受好像是樹已經插入非彙集的索引的葉子節點,而實際上是存放在其餘位置了
以必定的頻率和狀況進行Insert Buffer和輔助索引頁子節點的merge(合併)操做,一般會將多個插入操做一塊兒進行merge,這就大大的提高了非彙集索引的插入性能。
只有知足上面兩個必要條件時,InnoDB存儲引擎纔會使用Insert Buffer來提升插入性能。
那爲何必須知足上面兩個條件呢?
第一點索引是非彙集索引就不用說了,人家彙集索引原本就是順序的也不須要你
第二點必須不是惟一(unique)的,由於在寫入Insert Buffer時,數據庫並不會去判斷插入記錄的惟一性。若是再去查找確定又是離散讀取的狀況了,這樣InsertBuffer就失去了意義。
咱們可使用命令SHOW ENGINE INNODB STATUS來查看Insert Buffer的信息:
------------------------------------- INSERT BUFFER AND ADAPTIVE HASH INDEX ------------------------------------- Ibuf: size 7545, free list len 3790, seg size 11336, 8075308 inserts,7540969 merged sec, 2246304 merges ...
使用命令後,咱們會看到不少信息,這裏咱們只看下INSERT BUFFER 的:
seg size 表明當前Insert Buffer的大小 11336*16KB
free listlen 表明了空閒列表的長度
size 表明了已經合併記錄頁的數量
Inserts 表明了插入的記錄數
merged recs 表明了合併的插入記錄數量
merges 表明合併的次數,也就是實際讀取頁的次數
merges:merged recs大約爲1∶3,表明了Insert Buffer 將對於非彙集索引頁的離散IO邏輯請求大約下降了2/3
說了這麼多針對於Insert Buffer的好處,但目前Insert Buffer也存在一個問題:
即在寫密集的狀況下,插入緩衝會佔用過多的緩衝池內存(innodb_buffer_pool),默認最大能夠佔用到1/2的緩衝池內存。
佔用了過大的緩衝池必然會對其餘緩衝池操做帶來影響
MySQL5.5以前的版本中其實都叫作Insert Buffer,以後優化爲 Change Buffer
能夠看作是 Insert Buffer 的升級版。
插入緩衝( Insert Buffer)這個其實只針對 INSERT 操做作了緩衝,而Change Buffer 對INSERT、DELETE、UPDATE都進行了緩衝,因此能夠統稱爲寫緩衝,其能夠分爲:
Insert Buffer
Delete Buffer
Purgebuffer
Insert Buffer究竟是個什麼?
其實Insert Buffer的數據結構就是一棵B+樹。
在MySQL 4.1以前的版本中每張表有一棵Insert Buffer B+樹
目前版本是全局只有一棵Insert Buffer B+樹,負責對全部的表的輔助索引進行Insert Buffer
這棵B+樹存放在共享表空間ibdata1中
如下幾種狀況下 Insert Buffer會寫入真正非彙集索引,也就是所說的Merge Insert Buffer
一句話歸納下:
Insert Buffer 就是用於提高非彙集索引頁的插入性能的,其數據結構相似於數據頁的一個B+樹,物理存儲在共享表空間ibdata1中 。