唯一索引不能用Change Buffer,根本原因是写入时必须立即校验唯一性,而校验强制要求索引页加载进内存;一旦页已在内存,直接修改比缓存再合并更高效。

唯一索引不能用 Change Buffer,根本原因只有一个:写入时必须立即校验唯一性,而校验动作强制要求索引页被加载进内存——既然页已在内存,缓存修改就失去了意义。
唯一索引写入必须做唯一性检查
执行 INSERT 或 UPDATE 时,如果目标列上有唯一索引(包括 PRIMARY KEY 和 UNIQUE 索引),InnoDB 必须确认该键值是否已存在。这个判断不能靠猜,也不能延后,必须基于完整、最新的索引页数据。
这意味着:
- InnoDB 会立即发起一次磁盘随机读,把对应索引页从磁盘载入
Buffer Pool - 在内存中完成键值比对,再决定是否允许插入或更新
- 一旦页已在内存,直接修改它比“先记到
Change Buffer、等下次读再合并”更高效、更简单
普通索引为什么能用 Change Buffer
普通索引(非唯一二级索引)不承担唯一性约束,写入时无需校验键值是否重复。InnoDB 只需把变更操作(IBUF_OP_INSERT / IBUF_OP_DELETE)暂存到 Change Buffer 中,语句即可返回。
关键区别在于:
-
Change Buffer只对“索引页不在Buffer Pool中”的场景生效 - 普通索引的变更可以安全延迟合并,不影响事务可见性和一致性
- 合并(
Merge)发生在后续读取该页、后台线程调度或Change Buffer自身触发时
哪些索引明确被 Change Buffer 排除
不只是唯一索引被排除,以下索引类型同样无法使用 Change Buffer:
- 聚簇索引(即主键索引)——它本身就是数据存储结构,不适用“缓存索引变更”逻辑
- 全文索引(
FULLTEXT)和空间索引(SPATIAL)——内部结构与 B+ 树差异大,Change Buffer未适配 - 含降序键的索引(如
INDEX idx(a DESC, b ASC))——MySQL 目前不支持对其启用Change Buffer
innodb_change_buffer_max_size 不影响唯一索引行为
这个参数只控制 Change Buffer 内存上限(默认 25,表示占 Buffer Pool 的 25%),但它不会让唯一索引“变普通”。即使你把它调到 50,唯一索引的写入依然绕过 Change Buffer,因为底层校验逻辑不可绕过。
真正影响 Change Buffer 是否生效的,是索引定义本身 + 当前页是否在内存中 —— 这两点才是实际开关。
容易忽略的是:哪怕表上只有 1 个唯一索引,其余全是普通索引,那唯一索引部分的写入仍会触发随机读,而普通索引部分可能走 Change Buffer。这种混合场景下,性能表现其实是分层的,不是全表统一优化。


















