这是《MySQL 8.0 源码与内核实战》的独立章节版。本章从概念、实操和生产排查三个视角展开,代码块保留了原书可直接运行的版本。 Change Buffer 优化二级索引写入,AHI 加速热点页内记录定位。两者都受访问模式影响,并非总是有效。
17.1 Change Buffer
当二级索引页不在 Buffer Pool 时,InnoDB 可以先缓存插入或删除操作,避免立即读页。
insert secondary index
-> page in buffer pool?
|-- yes: modify directly
+-- no:
|-- unique index: must read page to check
+-- non-unique: buffer change
-> merge later
适用:
- 非唯一二级索引;
- 写多读少;
- 索引页访问分散;
- 二级索引较多;
- 页不在内存。
不适合:
- 唯一索引;
- 写后立刻读;
- 热点索引;
- 内存充足且命中率极高;
- 只读或大量顺序维护场景。
17.2 Merge
background or page access
-> read index page
-> apply buffered changes
-> write redo
-> remove change record
合并可能造成延迟抖动,尤其在读取冷索引或后台批量 merge 时。
观测:
SHOW GLOBAL STATUS LIKE 'Innodb_ibuf%';
关注:
- merge 次数;
- merge 耗时;
- slot 使用;
- size;
- segment size。
17.3 参数
| 参数 | 说明 |
|---|---|
innodb_change_buffering |
开启操作类型 |
innodb_change_buffer_max_size |
最大占 Buffer Pool 比例 |
8.0 部分小版本对 change buffer 支持范围有变化,使用前应确认当前版本文档和源码条件。
17.4 AHI
自适应哈希索引为热点页建立索引项到记录位置的哈希缓存:
index tuple prefix
-> hash
-> page and record position
适用:
- 等值查询;
- 热点页;
- 相同前缀模式;
- 页内记录较多;
- B+Tree 下降成本明显。
不适合:
- 范围扫描;
- 模式极其分散;
- 写入频繁导致哈希维护成本高;
- latch 争用明显。
17.5 AHI 观测
SHOW GLOBAL STATUS LIKE 'Innodb_hash%';
重点:
| 状态 | 含义 |
|---|---|
| searches | 命中搜索 |
| searches_run | 执行次数 |
| nodes | 节点数 |
若哈希搜索比例不高但争用高,可评估关闭:
SET GLOBAL innodb_adaptive_hash_index=OFF;
变更要逐项观测,不能盲目跟从网上建议。
17.6 源码入口
| 文件 | 内容 |
|---|---|
ibuf0ibuf.cc |
Change Buffer |
btr0sea.cc |
AHI |
ha0ha.cc |
哈希辅助 |
断点:
b ibuf_insert
b btr_search_guess_on_hash
17.7 判断方法
问题:二级索引写入慢
-> buffer hit rate
-> ibuf merge status
-> index cardinality
-> whether unique
问题:等值查询 CPU 高
-> AHI searches
-> mutex waits
-> page access pattern
本章小结
Change Buffer 用延迟合并降低冷二级索引写入 IO,AHI 用哈希降低热点页定位成本。二者都依赖访问模式,必须结合状态指标和 latch 争用判断收益。
思考题
- 为什么唯一索引不能直接使用 Change Buffer?
- Change Buffer merge 何时发生?
- AHI 对范围查询为什么收益有限?
- 如何判断 AHI 是否引发争用?
- 内存充足时 Change Buffer 是否一定有收益?