你插入MySQL的數據真的存到表裏了麼?

你插入MySQL的數據真的存到表裏了麼?

如今有這麼一個問題:當你執行一條insert語句以後,插入的數據就已經保存在磁盤中了麼?mysql

答案是不必定 ,那是爲何呢?首先來了解一下MySQL在InnoDB存儲引擎中,數據是怎麼存儲的。sql

1. InnoDB數據存儲單元

同大多數數據庫同樣,InnoDB有頁(Page)的概念(也能夠稱爲塊),頁是InnoDB磁盤管理的最小單位。在InnoDB存儲引擎中,默認每一個頁的大小爲16 KB。而從InnoDB 1.2.x版本開始,能夠經過參數InnoDB_page_size將頁的大小設置爲4 K、8 K、16 K。若設置完成,則全部表中頁的大小都爲InnoDB_page_size,不能夠對其再次進行修改。除非經過mysqldump導入和導出操做來產生新的庫。數據庫

file

InnoDB的數據是按數據頁爲單位來讀寫的。也就是說,當須要讀一條記錄的時候,並非將這個記錄自己從磁盤讀出來,而是以頁爲單位,將其總體讀入內存。緩存

而將數據從磁盤讀入內存涉及隨機IO的訪問,是數據庫裏面成本最高的操做之一,因此爲了減小磁盤IO,InnoDB設計了change buffer這個機制。函數

2. change buffer

在MySQL 5.5以前的版本中,因爲只支持緩存insert操做,因此最初叫作insert buffer,只是後來的版本中支持了更多的操做類型緩存,才改叫change buffer,這也是爲何代碼中有大量的ibuf前綴開頭的函數或變量。性能

然而使用change buffer須要同時知足兩個條件:spa

(1) 索引是輔助索引

插入聚簇索引通常是順序的,通常不須要磁盤的隨機讀取,因此不須要使用change buffer線程

(2) 索引不是惟一的設計

輔助索引不能是惟一的,由於在插入緩衝時,數據庫並不去查找索引頁來判斷插入的記錄的惟一性。若是去查找確定又會有離散讀取的狀況發生,從而致使change buffer失去了意義。日誌

3. change buffer的底層實現

change buffer底層結構是一顆全局的B+樹,負責對全部的表空間進行change buffer。

4. merge buffer

從上文可知Change Buffer是一棵B+樹。當須要實現插入記錄的輔助索引頁不在緩衝池中,輔助索引記錄首先會插入到這棵B+樹中。那麼Insert Buffer中的記錄什麼時候合併(merge)到真正的輔助索引中呢?

merge操做可能發生在如下幾種狀況下

  • 輔助索引頁被讀到緩存中
  • Change buffer bitmap頁追蹤到的輔助頁已無可用空間
  • master thread

第一種狀況爲當輔助索引頁被讀取到緩衝池中時,例如這在執行正常的SELECT查詢操做,這時須要檢查Insert Buffer Bitmap頁,而後確認該輔助索引頁是否有記錄存放於Insert Buffer B+樹中。如有,則將Insert Buffer B+樹中該頁的記錄插入到該輔助索引頁中。對該頁屢次的記錄操做經過幾回操做合併到了原有的輔助索引頁中,所以性能會有大幅提升。

第二種狀況Insert Buffer Bitmap 頁用來追蹤每一個輔助索引頁的可用空間,並至少有1/32頁的空間。若插入輔助索引記錄時檢測到插入記錄後可用空間會小於1/32頁,則會強制進行一個合併操做,即強制讀取輔助索引頁,將Insert Buffer B+樹中該頁的記錄及待插入的記錄插入到輔助索引頁中。這就是上述所說的第二種狀況。

第三種狀況就是在Master Thread線程中每秒或每10秒會進行一次Merge Change Buffer的操做,不一樣之處在於根據線程的工做狀態每次進行merge操做的頁的數量不一樣。

5. change buffer的使用場景

change buffer主要做用是將記錄的變動緩存下來,merge的時候是真正進行數據更新的時刻,因此在一個數據頁作merge以前,change buffer記錄的變動越多(也就是這個頁面上要更新的次數越多),收益就越大。

所以,對於寫多讀少的業務來講,頁面在寫完之後立刻被訪問到的機率比較小,此時change buffer的使用效果最好。這種業務模型常見的就是帳單類、日誌類的系統。

相關文章
相關標籤/搜索