change buffer是针对非唯一二级索引的延迟合并机制,对insert、update、delete均生效,但排除unique和主键索引;其核心价值在于减少随机i/o,将多次读写延迟至合并时批量处理。

Change Buffer不是“插入专用”,而是针对非唯一二级索引的延迟合并机制
很多人误以为Change Buffer(旧称Insert Buffer)只优化INSERT,其实它对UPDATE、DELETE涉及二级索引的修改同样生效。关键在于:它只作用于**非唯一二级索引**(UNIQUE索引和主键索引被完全排除)。这是因为唯一性检查必须实时读取完整索引页——InnoDB无法在缓存变更时跳过这个校验,否则会破坏约束。所以当你建了UNIQUE KEY (email),对该字段的INSERT就绕过Change Buffer,直接触发磁盘随机读;而普通INDEX (status)上的更新,则大概率走Change Buffer路径。
核心收益来自避免4次/行的随机I/O放大
一张有4个非唯一二级索引的表,每INSERT一行,InnoDB本需:① 读聚簇索引页(通常顺序,成本低);② 读4个二级索引页(随机,高成本);③ 修改并写回这4个页(又是4次随机写)。Change Buffer把步骤②和③压到后续合并时批量处理——实际只产生1次redo log写入(记录变更本身),而把4次磁盘读+4次磁盘写推迟到索引页被自然加载进Buffer Pool时再执行。这意味着:写吞吐量不再被磁盘IOPS卡死,尤其在SSD或机械盘上效果显著。但要注意:innodb_change_buffer_max_size默认值是25(即占Buffer Pool的25%),如果业务写入压力极大,这个上限可能成为瓶颈。
merge时机不可控,读放大风险真实存在
Change Buffer里的变更不会永远躺着,它会在三个时机被强制merge:① 对应索引页被读入Buffer Pool(比如你查WHERE status = 1,该页加载时立刻合并);② 后台线程定期扫描(由innodb_io_capacity调节频率);③ 实例关闭前强制刷出。问题在于:如果某张表的某个二级索引长期不被查询,它的Change Buffer内容可能堆积很久,导致后续第一次访问该索引页时,要一次性合并几十甚至上百条变更,造成明显延迟。监控时重点看Innodb_buffer_pool_read_requests与Innodb_buffer_pool_reads的比值,如果后者突增,且Innodb_change_buffer_merge_operations也同步飙升,大概率就是merge集中爆发了。
唯一索引禁用、全表扫描无感、小表几乎无效
以下场景Change Buffer完全不工作:
- 任何含
UNIQUE或PRIMARY KEY约束的索引操作 - Buffer Pool足够大,能把所有热索引页常驻内存(此时变更直接在内存页上做,无需缓冲)
- 表非常小,索引页全部在Buffer Pool中(
SHOW ENGINE INNODB STATUS里看Dictionary memory allocated和索引页数可辅助判断)











