簡介
變更緩沖區(qū)(原來的Insert Buffer)是一種特殊的數(shù)據(jù)結(jié)構(gòu),存儲位置在:
- 緩沖池;
- 磁盤的系統(tǒng)表空間;
大多數(shù)場景,輔助索引頁的訪問都會造成隨機(jī)的IO,相對順序IO來講效率非常差,對于輔助索引數(shù)據(jù)的INSERT,UPDATE或DELETE操作,對輔助索引操作來說,性能影響很大。需要去磁盤掃描輔助索引,數(shù)據(jù)量大的時候通常會有多次的隨機(jī)IO,才找到對應(yīng)輔助索引頁。因此Change Buffer正是來解決這個問題的。
Change Buffer工作原理

輔助索引數(shù)據(jù)的INSERT,UPDATE或DELETE操作,innoDB首先判斷輔助索引的頁是否在緩沖池中,如果在,則直接操作;如果不在,則先放到緩沖池的Change Buffer中,然后通過后臺線程按照一定的頻率和情況進(jìn)行Change Buffer和輔助索引頁的merge(合并)操作,通常能將多次的操作合并成一次操作(一個索引頁包含多個索引數(shù)據(jù)),這就大大提高了輔助索引數(shù)據(jù)操作的性能,可以通過innodb_change_buffer_max_size調(diào)整變更緩沖大小,默認(rèn)是25,最大只能設(shè)置為50,按照百分比取值。
Change Buffer的使用需要滿足以下兩個條件:
- 索引是輔助索引;
- 索引不是唯一的;
當(dāng)滿足以上兩個條件的時候,InnoDB會使用Change Buffer,這樣就能提高DML操作性能。當(dāng)然該機(jī)制也有一定的弊端:比如,大量的DML操作導(dǎo)致大量的Change Buffer沒有合并到輔助索引頁中,如果發(fā)生了宕機(jī),重啟恢復(fù)需要很長的時間。
考慮一個問題,為什么Change Buffer規(guī)定索引不是唯一的?
答案很明顯,Change Buffer設(shè)計的初衷就是為了減少磁盤隨機(jī)IO,如果是唯一索引,需要多一步索引唯一性校驗是需要訪問磁盤的,如果是這樣就會失去了意義。
Change Buffer數(shù)據(jù)結(jié)構(gòu)
Change Buffer的數(shù)據(jù)結(jié)構(gòu)實際上是一顆B+ Tree,由所有表進(jìn)行Change Buffer的非唯一輔助索引組成。
B+ Tree每個節(jié)點存儲內(nèi)容如下:
| space | marker | offset | metadata | secondary index record |
|---|---|---|---|---|
| 表空間id 占用4個字節(jié) |
區(qū)分新老版本 占用1個字節(jié) |
索引頁偏移量,即page_no 占用4個字節(jié) |
元數(shù)據(jù) 占用4個字節(jié) |
輔助索引記錄 |
metadata存儲內(nèi)容如下:
| IBUF_REC_OFFECT_COUNT | IBUF_REC_OFFECT_TYPE | IBUF_REC_OFFECT_FLAGS |
|---|---|---|
| 用來排序每個記錄進(jìn)入Change Buffer的順序 占用2個字節(jié) |
對用緩存的操作類型 占用1個字節(jié) |
表示行格式 占用1個字節(jié) |
為了保證每次都能merge成功,還需要有一個特殊的頁來標(biāo)記每個輔助索引頁(space,page_no)的可用空間。這個就是Insert Buffer Bitmap,每個Insert Buffer Bitmap頁用來追蹤16384個輔助索引頁。每個輔助索引頁在Insert Buffer Bitmap存儲結(jié)構(gòu)如下:
| IBUF_BITMAP_FREE | IBUF_BITMAP_BUFFERED | IBUF_BITMAP_IBUF |
|---|---|---|
| 表示該輔助索引頁的可用空間(占用2個bit): 0 表示無可用空間 1 表示剩余空間>1/32 2 表示剩余空間>1/16 3 表示剩余空間>1/8 |
1 表示該輔助索引頁有記錄被緩存到Change Buffer中(占用1個bit) | 1 表示該頁是Change Buffer B+ Tree的頁 |
Change Buffer工作狀態(tài)
可以通過SHOW ENGINE INNODB STATUS;查看Change Buffer工作狀態(tài):
如上圖所示,首先看下Ibuf那一行:
- size:表示已經(jīng)合并到輔助索引頁的數(shù)量;
- free list len:表示空閑列表長度;
- seg size:表示當(dāng)前Change Buffer的大小,2*16KB;
- merges:表示合并的次數(shù);
- merged operations:表示每個具體操作合并的次數(shù);
- insert:表示插入操作;
- delete mark:表示刪除標(biāo)記操作;
- delete:表示物理刪除操作;
- discarded operations:表示操作的表已經(jīng)被刪除,不需要合并的每個具體操作次數(shù);
InnoDB提供了innodb_change_buffering配置,可選值如下:
| 選項 | 說明 |
|---|---|
| inserts | 插入緩沖; |
| deletes | 刪除標(biāo)記緩沖; |
| changes | 更新緩沖,由兩個上面inserts、deletes組成; |
| purges | 緩沖在后臺發(fā)生的物理刪除操作; |
| all | 表示啟用上面所有; |
| none | 表示什么都不啟用; |
Change Buffer合并操作觸發(fā)
- 輔助索引頁被讀取到緩沖池:
當(dāng)輔助索引頁被讀取到緩沖池時,需要檢查Insert Buffer Bitmap頁IBUF_BITMAP_BUFFERED==1?如果是,則觸發(fā)合并操作; - Insert Buffer Bitmap頁追蹤到改輔助索引頁無可用空間時:
插入輔助索引頁時,檢測到此次插入后的輔助索引頁大小會<1/32,就會強(qiáng)制觸發(fā)合并操作; - Master Thread:每秒或每10秒觸發(fā)一次合并操作;在Change Buffer B+ Tree中,樹的節(jié)點根據(jù)(space, offset)排序。Master Thread會隨機(jī)選擇Change Buffer B+ Tree的一個節(jié)點,讀取從該節(jié)點開始到之后所需要的節(jié)點數(shù)量。比如Master Thread合并變更緩存的數(shù)量=5,那么就隨機(jī)選擇一個節(jié)點,從該節(jié)點之后的5個節(jié)點(包括第一個選中的節(jié)點)。