The change buffer is a special data structure that caches changes to secondary index pages when affected pages are not in the buffer pool. The buffered changes, which may result from INSERT, UPDATE, or DELETE operations (DML), are merged later when the pages are loaded into the buffer pool by other read operations.
change buffer/insert buffer是缓存非唯一索索引insert、update、delete操作时的记录,在其他操作加载索引数据到缓冲区时合并。
innodb在对非唯一索引做修改变更时,把数据插入insert buffer让事务觉得数据已刷新到硬盘提升事务执行效率,在根据内部算法逐步刷新到索引页,这样将多次索引操作合并为一次操作提升效率。
insert buffer会先将辅助索引的记录缓存起来,其前提必须保证一个索引页中缓存的记录不会引起页的分裂,缓存的数据过多时会主动读取索引页进行合并操作,innodb引擎有个insert buffer bitmap页记录每个辅助索引页的剩余空间,当剩余空间小于内部定义的阈值就必须主动进行一次合并操作,而insert buffer bitmap只能追踪一个辅助索引页2KB的可用空间,所以insert buffer只能缓存一个辅助索引页的总大小只有2KB.
insert buffer可以直接看着一个B+tree的索引树,因为结构和B+tree索引类似,当一个索引页数据发生合并操作时,insert buffer的索引树同样需要做平衡操作,就会对整个insert buffer索引树持有X-latch,阻塞其他对insert buffer的操作,当然这个X-latch持有时间是很短的,对于合并多个辅助索引的操作效率提升还是很明显。
合并数据时insert buffer加锁流程为:
index leaf page x-latch->insert buffer tree x-latch->insert buffer page x-latch->fsp(模块)x-latch
insert buffer加锁拥有优先级,当持有某一层的锁时不能再持有上一层的锁,这样和B+tree索引持锁方式有所不同,在insert buffer高并发时可以避免死锁发生。
In memory, the change buffer occupies part of the InnoDB buffer pool. On disk, the change buffer is part of the system tablespace, so that index changes remain buffered across database restarts.
内存中change buffer存于innodb缓冲区中,硬盘上存于系统表空间中,所以数据库重启之后也可以做合并操作,不会丢失数据。
innodb_change_buffering控制buffer空间存储什么类型产生的数据,可配置项有:
all:默认值,缓存插入、标记删除和后台物理清理
none:不缓存任何操作产生的数据
inserts:缓存insert产生的数据
deletes:缓存标记删除对辅助索引产生的变化
changes:inserts和deletes的合并项
purges:内部物理清除所产生的数据
innodb_change_buffer_max_size:设置insert buffer空间大小,默认为25,最大为50,该值为innodb_buffer_pool_size的百分比
insert buffer状态可以查看INSERT BUFFER AND ADAPTIVE HASH INDEX对应的值:
mysql> show engine innodb status\G;
-------------------------------------
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 138389, node heap has 0 buffer(s)
Hash table size 138389, node heap has 0 buffer(s)
Hash table size 138389, node heap has 0 buffer(s)
Hash table size 138389, node heap has 0 buffer(s)
Hash table size 138389, node heap has 0 buffer(s)
Hash table size 138389, node heap has 0 buffer(s)
Hash table size 138389, node heap has 1 buffer(s)
Hash table size 138389, node heap has 0 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
也可以在INFORMATION_SCHEMA库下表中也可以查询到占用缓冲区数据页的情况
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 |
+---------------------+-------------+-------------------------------+
| 41 | 32764 | 0.1251 |
+---------------------+-------------+-------------------------------+