唯⼀索引普通索引选择难题
面试经常被问,核⼼是需要回答到change buffer,那change buffer⼜是个什么东⻄呢?
当需要更新⼀个数据⻚时,如果数据⻚在内存中就直接更新,⽽如果这个数据⻚还没有在内存中的话,
在不影响数据⼀致性的前提下,InooDB会将这些更新操作缓存在change buffer中,这样就不需要从磁
盘中读⼊这个数据⻚了
在下次查询需要访问这个数据⻚的时候,将数据⻚读⼊内存,然后执⾏change buffer中与这个⻚有关的
操作,通过这种⽅式就能保证这个数据逻辑的正确性。
需要说明的是,虽然名字叫作change buffer,实际上它是可以持久化的数据。也就是说,change buffer
在内存中有拷⻉,也会被写⼊到磁盘上。
将change buffer中的操作应⽤到原数据⻚,得到最新结果的过程称为merge。
除了访问这个数据⻚会触发merge外,系统有后台线程会定期merge。在数据库正常关闭(shutdown)
的过程中,也会执⾏merge操作。
显然,如果能够将更新操作先记录在change buffer,减少读磁盘,语句的执⾏速度会得到明显的提升。
⽽且,数据读⼊内存是需要占⽤buffer pool的,所以这种⽅式还能够避免占⽤内存,提⾼内存利⽤率
那么,什么条件下可以使⽤change buffer呢?
对于唯⼀索引来说,所有的更新操作都要先判断这个操作是否违反唯⼀性约束。
要判断表中是否存在这个数据,⽽这必须要将数据⻚读⼊内存才能判断,如果都已经读⼊到内存了,那
直接更新内存会更快,就没必要使⽤change buffer了。
因此,唯⼀索引的更新就不能使⽤change buffer,实际上也只有普通索引可以使⽤。
change buffer⽤的是buffer pool⾥的内存,因此不能⽆限增⼤,change buffer的⼤⼩,可以通过参数
innodb_change_buffer_max_size来动态设置,这个参数设置为50的时候,表示change buffer的⼤⼩最
多只能占⽤buffer pool的50%。
将数据从磁盘读⼊内存涉及随机IO的访问,是数据库⾥⾯成本最⾼的操作之⼀,change buffer因为减少
了随机磁盘访问,所以对更新性能的提升是会很明显的
change buffer的使⽤场景
因为merge的时候是真正进⾏数据更新的时刻,⽽change buffer的主要⽬的就是将记录的变更动作缓存
下来,所以在⼀个数据⻚做merge之前,change buffer记录的变更越多(也就是这个⻚⾯上要更新的次
数越多),收益就越⼤。
因此,对于写多读少的业务来说,⻚⾯在写完以后⻢上被访问到的概率⽐较⼩,此时change buffer的使
⽤效果最好,这种业务模型常⻅的就是账单类、⽇志类的系统。
反过来,假设⼀个业务的更新模式是写⼊之后⻢上会做查询,那么即使满⾜了条件,将更新先记录在
change buffer,但之后由于⻢上要访问这个数据⻚,会⽴即触发merge过程。这样随机访问IO的次数不
会减少,反⽽增加了change buffer的维护代价,所以,对于这种业务模式来说,change buffer反⽽起到
了副作⽤