当前位置: 首页 > 后端技术 > Java

InnoDB学习(二)ChangeBuffer

时间:2023-04-01 21:25:50 Java

ChangeBuffer是InnoDB缓存区的一种特殊数据结构。当用户执行SQL改变非唯一索引时,如果索引对应的数据页不在缓存中,InnoDB不会直接Load磁盘数据到缓存的数据页中,而是对这些改变进行缓存操作。这些更改操作可能由插入、更新或删除操作(DML)触发。当磁盘数据被其他读取操作加载到缓存中时,缓存区的更改操作将合并到相应的缓存数据页中。ChangeBufferInnoDBChangeBuffer官方图如下所示,从图中可以看出以下信息:ChangeBuffer用于存储SQL变更操作,例如Insert/Update/Delete等SQL语句;ChangeBuffer中的每个更改操作都有其对应的数据页,并且数据页不会加载到缓存中;当ChangeBufferd中的变更操作对应的数据页被加载到缓存中时,InnoDB会将变更操作合并到数据页中;InnoDB会周期性地将ChangeBuffer中操作对应的数据页加载到缓存中,并进行Merge变更操作;根据我个人的理解,参考了官方的ChangeBuffer示例图,我画了如下更直观的ChangeBuffer示例图:ChangeBuffer的作用我们知道InnoDB推荐使用自增主键,主键值自增插入,可以顺序访问。与聚集索引不同,二级索引通常不是唯一的,并且以相对随机的顺序插入。同样,二级索引的更新和删除往往会影响索引树中不连续的二级索引数据页。对于二级索引数据变化引起的随机访问,如果每次都进行磁盘IO,显然会影响数据库的性能。因此,InnoDB不会立即执行数据页不在缓存中的二级索引的更改操作,而是先缓存更改操作,然后在某个时间将某个数据页上的所有更改操作合并到数据页中.通过变更操作缓存(ChangeBuffer),可以将同一数据页上的大量随机访问I/O组合起来。何时将ChangeBuffer工作流变更操作放入ChangeBuffer并非所有数据库中的操作都会进入ChangeBuffer。满足以下条件的数据库语句在执行阶段不会修改数据页,而是进入ChangeBuffer,SQL会修改数据库中的数据。;SQL语句不涉及唯一键的校验;SQL语句不需要返回变化的数据;涉及的数据页不在缓存中;ChangeBuffer被合并到原来的数据页我们知道change操作是缓存在ChangeBuffer中的,这些操作最终需要合并到数据库的数据页,合并的过程叫做Merge,那么在什么场景下会ChangeBuffer的合并操作被触发?访问变更操作对应的数据页;InnoDB后台定期Merge;数据库缓冲池空间不足;当数据库正常关闭时;,如果change操作修改的数据是唯一索引或者主键数据,那么InnoDB是无法将change操作缓存到ChangeBuffer中的。为什么?以用户表为例。用户表包含四个字段:主键ID、年龄、姓名和性别。非唯一索引被添加到年龄。初始数据及建表语句如下:用户ID123456789姓名陈二张三李四王五、赵六、孙奇、周跋、吴久、郑实、性别、男、女、男、女、男,男性,男性,男性,男性,男性,男性,年龄51020283556258090createtableuser_info(idintprimarykey,ageintnotnull,namevarchar(16),sexbool,key(age))engine=InnoDB;nonUniqueindexupdate假设我们使用SQL语句updateuser_infosetage=6whereid=1将ID=1的用户年龄修改为6,这个操作会同时修改年龄索引和行数据中的年龄。更新步骤如下:如果需要更改age索引页和行数据页在缓存中,直接更新缓存中的数据,并将数据页标记为脏页;如果要更改的age索引页和row数据页不在缓存中,直接更新SQL语句updateuser_infosetage=6whereid=1存储在ChangeBuffer中;唯一索引已更新新的假设是我们使用SQL语句updateuser_infosetid=2whereid=1将ID=1的用户ID修改为2,这个操作会同时修改聚簇索引和行数据。更新步骤如下:如果需要改变聚集索引和行数据页在缓存中,直接更新缓存中的数据,并将数据页标记为脏页;如果需要修改的聚簇索引页和行数据页不在缓存中,则需要将相应的数据页加载到缓存中,判断修改后的ID是否符合唯一键约束,然后修改缓存中的数据;可以看出,由于需要对唯一索引进行唯一性校验,所以在更新唯一索引时,必须将相应的数据页加载到缓存中进行校验,才能导致ChangeBuffer失效正常索引还是唯一索引通过上面的分析,我们知道那个uniqueindex不能用ChangeBuffer,那么实际使用中应该用normalindex还是uniqueindex呢?从等价查询性能来看:普通索引找到第一个满足条件的数据后,需要继续向后查找满足条件的数据;唯一索引找到第一个满足条件的数据后,不需要再向后查找,因为索引是唯一的;两者只差一个记录,这个记录会带来多大的性能差异呢?答案是,很少。因为InnoDB引擎以页为单位读取数据,在读取一条数据时,往往会将相邻的数据读入内存,所以向后查询几条数据带来的性能差异很小。从索引修改的角度来看:由于非唯一索引不能使用ChangeBuffer,索引的修改会造成大量的磁盘IO,影响数据库的性能。综上所述,如果业务中不需要数据库校验某个字段的唯一性,我们最好使用普通索引,而不是唯一索引。ChangeBuffer在什么情况下应用到ChangeBuffer上会有较大的性能提升呢?数据库中的大多数索引都是非唯一索引;生意是多写少读,或者写完不马上看;对应不适合使用ChangeBuffer的场景:第一,不适合的时候,上面分析过,当:数据库唯一Index;写入数据后,立即读取;ChangeBuffer相关参数innodb_change_buffer_max_size:配置写入缓冲区的大小,占整个缓冲池的比例。默认值为25%,最大值为50%。只有写多读少的业务才需要增加这个值。innodb_change_buffering:配置哪些写操作启用写缓冲,可以设置为all/none/inserts/deletes等。我是狐神,欢迎大家关注我的微信公众号:wzm2zsd本文首发于微信公众号,版权所有,禁止转载!