部分《??MySQL缓冲池(buffer pool),终于懂了??》介绍了InnoDB缓冲池的工作原理。简要回顾:MySQL数据存储包括内存和磁盘两部分;内存缓冲池(bufferpool)以页为单位缓存最热的数据页(datapages)和索引页(indexpages);InnoDB使用LRU算法的一个变体来管理缓冲池,可以解决“预读失败”和“缓冲池污染”的问题;毫无疑问,对于读请求,缓冲池可以减少磁盘IO,提高性能。问题来了,写请求怎么办?情况1如果要修改页号为4的索引页,而这个页恰好在缓冲池中。上图中数字1-2:直接修改缓冲池中的页面是内存操作;写入重做日志是一个磁盘顺序写操作;这是最有效的。画外音:像写日志一样顺序写是没有问题的,每秒几万次。是否存在一致性问题?它没有。读取时,会命中缓冲池中的页面;当缓冲池中的LRU数据被淘汰后,“脏页”将被刷新回磁盘;如果数据库异常崩溃,可以从重做日志中恢复数据;磁盘上呢?定期刷新磁盘,而不是每次都刷新,这样可以减少磁盘IO,提高MySQL的性能。画外音:批量写入是一种常见的优化方式。情况2如果要修改页号为40的索引页,而该页不在缓冲池中。这时候就有点麻烦了,如上图,需要1-3:首先,从磁盘加载需要40的索引页到缓冲池,一次随机磁盘读操作;修改缓冲池中的页面,一次内存操作;写入重做日志,磁盘顺序写操作;当没有命中缓冲池时,至少会产生一次磁盘IO。写多读少的业务场景还有优化空间吗?这是InnoDB考虑的问题,也是本文要讨论的写缓冲(changebuffer)。画外音:从名字就很容易看出写缓冲是一种减少磁盘IO,提高数据库写性能的机制。InnoDB的写缓冲区是什么?MySQL5.5之前称为insertbuffer,只针对insert做了优化;现在对delete和update也有效,称为writebuffer(changebuffer)。是非唯一二级索引页不在缓冲池中时的一个应用,写入该页时,磁盘页不会立即加载到缓冲池中,而只是记录缓冲变化(bufferchanges),等待未来的数据被读取,然后将数据合并回缓冲池。写缓冲的目的是减少写操作的磁盘IO,提高数据库性能。画外音:R是狗,这句话好长。InnoDB加入写缓冲区优化,上面的“case2”过程会发生什么?如果要修改页号为40的索引页,并且该页不在缓冲池中。添加writebuffer优化后,流程优化如下:将本次操作记录在writebuffer中,一次内存操作;写入重做日志,磁盘顺序写操作;它的性能类似于缓冲池中的索引页。画外音:如您所见,第40页没有加载到缓冲池中。是否存在一致性问题?也不会。数据库异常crash,可以从redolog中恢复数据;writebuffer不仅仅是一个内存结构,它还会被周期性的刷新到writebuffer系统表空间;当读取数据时,还有一个进程将数据合并到缓冲区中可以假设,稍后有请求查询索引页40的数据,此时的进程顺序如下编号1-3:加载索引页,缓冲池未命中,这个磁盘IO是不可避免的;从写缓冲区中读取相关信息;恢复索引页,放入缓冲池LRU;画外音:可以看到To,40页只有在真正读取的时候才会加载到缓冲池中。还有一个遗漏的问题,为什么writebuffer优化只适用于非唯一的普通索引页?在InnoDB中,聚簇索引和二级索引的异同在《??1分钟了解MyISAM与InnoDB的索引差异??》中有详细介绍,不再展开。如果索引设置了唯一性(unique)属性,InnoDB在执行修改操作时必须进行唯一性检查。也就是说,即使索引页不在缓冲池中,也无法避免磁盘上的页读取(否则如何检查是否唯一?),此时应该直接将相应的页放入bufferpool然后修改而不是整个writebuffer是个蛀虫。除了正在访问的数据页,还有哪些场景会触发缓冲区中的数据被刷新?还有几种情况会刷新缓冲区中的数据:当有后台线程时,数据库会被认为是空闲的;当数据库缓冲池不够时;当数据库正常关闭时;当重做日志已满时;画外音:几乎不会出现redo日志已满,整个数据库处于无法写入的不可用状态。哪些业务场景适合开启InnoDB的writebuffer机制?不合适的时候再说吧。上面分析过,当:数据库是唯一索引;或者,写入一条数据后,立即读取;在这两类场景中,当写操作正在进行时(操作后),已经是为了读取页面,相应的页面不得不放入缓冲池中。这时候写缓存就成了负担,增加了复杂度。什么时候使用写缓冲比较合适,如果:大多数数据库都是非唯一索引;生意是多写少读,或者写完不马上看;您可以使用写缓冲来替换每次写入都需要磁盘IO的SQL。优化定期批量写入磁盘。画外音:例如,计费交易。InnoDB中有哪些参数符合上述原则?还有两个更重要的参数。(1)参数:innodb_change_buffer_max_size简介:配置写缓冲区的大小,占整个缓冲池的比例。默认值为25%,最大值为50%。画外音:对于写多读少的商家,需要加大这个值。对于读多写少的企业来说,25%其实太多了。(2)参数:innodb_change_buffering介绍:配置哪些写操作启用写缓冲,可以设置为all/none/inserts/deletes等,希望大家有所收获。想法比结论更重要。
