什麼是Change Buffer?
Change Buffer是一種用於緩存二級索引頁變化的特殊數據結構,是緩衝池中一塊獨立的區域。當需要修改的二級索引頁不在緩衝池中而在磁盤中時,會將這些索引頁的變化緩存在change buffer中。
爲什麼二級索引需要Change Buffer?
-
減少隨機讀取IO
對於聚集索引頁,DML操作帶來的數據磁盤讀取和緩存修改往往是順序的、集中的,這就很好地利用了聚集索引的優點,但隨着聚集索引頁的順序IO,各個二級索引頁的讀取和修改通常是隨機IO的。而Change buffer將分散的、未緩存的二級索引頁的變化進行緩存而非直接從磁盤中讀取索引頁,待到其他操作需要訪問二級索引時,只需將change buffer中的變化緩存合併然後加入緩衝池就行了,這樣就大大地減少了磁盤隨機讀取的IO。
-
定期批量寫入索引變化
爲了避免change buffer使用過多,二級索引頁的變化也必須定期地寫入磁盤,這個操作叫做purge,相較於立即將索引頁變化寫入磁盤而言,這種批量的寫入自然是更加高效。InnoDB主線程會在服務器空閒時進行purge操作
但需要注意的是,當需要更新的二級索引頁過多時,change buffer的purge操作可能需要花費幾個小時,期間,磁盤IO會增加,可能會嚴重影響磁盤IO密集的查詢。合理配置change buffer可避免這種情況的發生。
如何配置change buffer?
可以用innodb_change_buffering系統變量控制change buffer相關的行爲。可以控制change buffer只對部分類操作生效。該變量的值和含義如下:
-
all
默認值,表示緩存所有DML語句和物理purge操作的索引頁變化。
-
none
不對任何操作緩存,相當於禁用
-
inserts
只緩存insert
-
deletes
只緩存標記性delete操作
-
changes
只緩存寫入和標記性delete
-
purges
只緩存後臺物理刪除操作
注意:
innodb_change_buffering參數可動態修改,只對修改後發生的操作生效,修改前已緩存的索引頁不受影響
可以用innodb_change_buffer_max_size變量控制change buffer區域的最大大小,表示佔緩衝池總大小的百分點數。默認爲25。最大可以設置爲50。
當DML語句量較多時,可以適當擴大innodb_change_buffer_max_size.反則反之。
如何監控Change buffer的使用?
-
show engine innodb status
命令可用於查看change buffer的使用情況,包含於INSERT BUFFER AND ADAPTIVE HASH INDEX
部分:
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
insert 0, delete mark 0, delete 0
discarded operations:
insert 0, delete mark 0, delete 0
Hash table size 4425293, used cells 32, node heap has 1 buffer(s)
13577.57 hash searches/s, 202.47 non-hash searches/s
Ibuf: size 1, free list len 0, seg size 2, 0 merges
size爲當前使用的change buffers頁數,seg size表示change buffer分配的總頁數。
- 也可以用下面的SQL查看change buffer更詳細的使用統計
select * from information_schema.innodb_metrics
where subsystem like 'change_buffer'\G
*************************** 1. row ***************************
NAME: ibuf_merges_insert
SUBSYSTEM: change_buffer
COUNT: 198469
MAX_COUNT: 198469
MIN_COUNT: NULL
AVG_COUNT: 0.13473886448652062
COUNT_RESET: 198469
MAX_COUNT_RESET: 198469
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
TIME_ENABLED: 2019-07-30 16:04:56
TIME_DISABLED: NULL
TIME_ELAPSED: 1472990
TIME_RESET: NULL
STATUS: enabled
TYPE: status_counter
COMMENT: Number of inserted records merged by change buffering
*************************** 2. row ***************************
NAME: ibuf_merges_delete_mark
SUBSYSTEM: change_buffer
COUNT: 35361
MAX_COUNT: 35361
MIN_COUNT: NULL
AVG_COUNT: 0.02400627295500988
COUNT_RESET: 35361
MAX_COUNT_RESET: 35361
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
TIME_ENABLED: 2019-07-30 16:04:56
TIME_DISABLED: NULL
TIME_ELAPSED: 1472990
TIME_RESET: NULL
STATUS: enabled
TYPE: status_counter
COMMENT: Number of deleted records merged by change buffering
*************************** 3. row ***************************
NAME: ibuf_merges_delete
SUBSYSTEM: change_buffer
COUNT: 875
MAX_COUNT: 875
MIN_COUNT: NULL
AVG_COUNT: 0.0005940298304808587
COUNT_RESET: 875
MAX_COUNT_RESET: 875
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
TIME_ENABLED: 2019-07-30 16:04:56
TIME_DISABLED: NULL
TIME_ELAPSED: 1472990
TIME_RESET: NULL
STATUS: enabled
TYPE: status_counter
COMMENT: Number of purge records merged by change buffering
*************************** 4. row ***************************
NAME: ibuf_merges_discard_insert
SUBSYSTEM: change_buffer
COUNT: 0
MAX_COUNT: 0
MIN_COUNT: NULL
AVG_COUNT: 0
COUNT_RESET: 0
MAX_COUNT_RESET: 0
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
TIME_ENABLED: 2019-07-30 16:04:56
TIME_DISABLED: NULL
TIME_ELAPSED: 1472990
TIME_RESET: NULL
STATUS: enabled
TYPE: status_counter
COMMENT: Number of insert merged operations discarded
*************************** 5. row ***************************
NAME: ibuf_merges_discard_delete_mark
SUBSYSTEM: change_buffer
COUNT: 0
MAX_COUNT: 0
MIN_COUNT: NULL
AVG_COUNT: 0
COUNT_RESET: 0
MAX_COUNT_RESET: 0
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
TIME_ENABLED: 2019-07-30 16:04:56
TIME_DISABLED: NULL
TIME_ELAPSED: 1472990
TIME_RESET: NULL
STATUS: enabled
TYPE: status_counter
COMMENT: Number of deleted merged operations discarded
*************************** 6. row ***************************
NAME: ibuf_merges_discard_delete
SUBSYSTEM: change_buffer
COUNT: 0
MAX_COUNT: 0
MIN_COUNT: NULL
AVG_COUNT: 0
COUNT_RESET: 0
MAX_COUNT_RESET: 0
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
TIME_ENABLED: 2019-07-30 16:04:56
TIME_DISABLED: NULL
TIME_ELAPSED: 1472990
TIME_RESET: NULL
STATUS: enabled
TYPE: status_counter
COMMENT: Number of purge merged operations discarded
*************************** 7. row ***************************
NAME: ibuf_merges
SUBSYSTEM: change_buffer
COUNT: 178009
MAX_COUNT: 178009
MIN_COUNT: NULL
AVG_COUNT: 0.12084874982179106
COUNT_RESET: 178009
MAX_COUNT_RESET: 178009
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
TIME_ENABLED: 2019-07-30 16:04:56
TIME_DISABLED: NULL
TIME_ELAPSED: 1472990
TIME_RESET: NULL
STATUS: enabled
TYPE: status_counter
COMMENT: Number of change buffer merges
*************************** 8. row ***************************
NAME: ibuf_size
SUBSYSTEM: change_buffer
COUNT: 1
MAX_COUNT: 1
MIN_COUNT: NULL
AVG_COUNT: 0.0000006788912348352671
COUNT_RESET: 1
MAX_COUNT_RESET: 1
MIN_COUNT_RESET: NULL
AVG_COUNT_RESET: NULL
TIME_ENABLED: 2019-07-30 16:04:56
TIME_DISABLED: NULL
TIME_ELAPSED: 1472990
TIME_RESET: NULL
STATUS: enabled
TYPE: status_counter
COMMENT: Change buffer size in pages
8 rows in set (0.01 sec)
-
information_schema.innodb_buffer_page
系統表中存放的是每個緩衝池中的頁的元數據,也可以用於統計change buffer的使用情況:
mysql> SELECT (SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE
WHERE PAGE_TYPE LIKE 'IBUF%') AS change_buffer_pages,
(SELECT COUNT(*) FROM INFORMATION_SCHEMA.INNODB_BUFFER_PAGE) AS total_pages,
(SELECT ((change_buffer_pages/total_pages)*100))
AS change_buffer_page_percentage;
+---------------------+-------------+-------------------------------+
| change_buffer_pages | total_pages | change_buffer_page_percentage |
+---------------------+-------------+-------------------------------+
| 25 | 8192 | 0.3052 |
+---------------------+-------------+-------------------------------+