InnoDB学习(二)之ChangeBuffer

LogicCat
• 阅读 1027

ChangeBuffer是InnoDB缓存区的一种特殊的数据结构,当用户执行SQL对非唯一索引进行更改时,如果索引对应的数据页不在缓存中时,InnoDB不会直接加载磁盘数据到缓存数据页中,而是缓存对这些更改操作。这些更改操作可能由插入、更新或删除操作(DML)触发。缓存区的更改操作会在磁盘数据被其它读操作加载到缓存中时合并到对应的缓存数据页中。

ChangeBuffer

InnoDB ChangeBuffer的官方示意图如下所示,从图中可以看出以下信息:

  1. ChangeBuffer用于存储SQL变更操作,比如Insert/Update/Delete等SQL语句;
  2. ChangeBuffer中的每个变更操作都有其对应的数据页,并且该数据页未加载到缓存中;
  3. 当ChangeBufferd中变更操作对应的数据页加载到缓存中后,InnoDB会把变更操作Merge到数据页上;
  4. InnoDB会定期加载ChangeBuffer中操作对应的数据页到缓存中,并Merge变更操作;

InnoDB学习(二)之ChangeBuffer

基于个人理解并参考官方的ChangeBuffer示例图,我绘制了以下更为直观的的ChangeBuffer示例图:

InnoDB学习(二)之ChangeBuffer

ChangeBuffer的作用

我们知道InnoDB推荐使用自增主键,插入时主键值时递增的,可以顺序访问。与聚簇索引不同,二级索引通常是不是唯一的,并且以相对随机的顺序插入。类似的,二级索引的更新和删除经常也会影响索引树中不相邻的二级索引数据页。

对于二级索引数据变更引起的随机访问,如果每次都进行磁盘IO显然会影响数据库的性能。因此InnoDB不会立即执行数据页不在缓存中的二级索引的变更操作,而是先将变更操作缓存起来,在某个时刻再将某一个数据页上面的所有变更操作合并到该数据页上,通过变更操作缓存(ChangeBuffer)可合并同一个数据页上的大量随机访问I/O。

ChangeBuffer工作流程

变更操作什么时候放入ChangeBuffer

并不是数据库中的所有操作都会进入ChangeBuffer,满足以下条件的数据库语句,在执行阶段不会修改数据页,而是会进入ChangeBuffer,

  1. SQL会修改数据库中的数据;
  2. SQL语句不涉及唯一键的校验;
  3. SQL语句不需要返回变更后的数据;
  4. 涉及的数据页不在缓存中;

ChangeBuffer合并到原数据页

我们知道,ChangeBuffer中缓存了变更操作,这些操作最终需要合并到数据库的数据页,合并过程称为Merge,那么在什么场景下会触发ChangeBuffer的Merge操作呢?

  1. 访问变更操作对应的数据页;
  2. InnoDB后台定期Merge;
  3. 数据库BufferPool空间不足;
  4. 数据库正常关闭时;
  5. RedoLog写满时;

为什么ChangeBuffer只缓存非唯一索引数据

ChangeBuffer仅仅适用于变更的数据未为非唯一索引的情况,如果变更操作修改的数据为唯一索引或者主键数据,那么InnoDB无法把变更操作缓存到ChangeBuffer,这是为什么呢?

以一张用户表为例,用户表包含主键ID、年龄、姓名和性别四个字段,其中年龄添加了非唯一索引,初始数据及建表语句如下所示:

用户ID123456789
姓名陈尔张散李思王舞赵流孙期周跋吴酒郑史
性别
年龄51020283556258090
create table user_info
(
    id   int primary key,
    age  int not null,
    name varchar(16),
    sex  bool,
    key(age)
)engine=InnoDB;

非唯一索引更新

假设我们使用SQL语句update user_info set age=6 where id=1修改ID=1的用户的年龄为6,该操作会同时修改年龄索引以及行数据中的年龄,更新步骤如下:

  • 如果需要更改的年龄索引页和行数据页在缓存中,直接更新缓存中的数据,并把数据页标记为脏页;
  • 如果需要更改的年龄索引页和行数据页不在缓存中,直接把SQL语句update user_info set age=6 where id=1存储到ChangeBuffer;

唯一索引更新

假设我们使用SQL语句update user_info set id=2 where id=1修改ID=1的用户的ID为2,该操作会同时修改聚簇索引和行数据,更新步骤如下:

  • 如果需要更改的聚簇索引和行数据页在缓存中,直接更新缓存中的数据,并把数据页标记为脏页;
  • 如果需要更改的聚簇索引页和行数据页不在缓存中,需要把对应的数据页加载到缓存中,判断修改之后ID是不是符合唯一键约束,然后修改缓存中的数据;

可以看到,由于唯一索引需要进行唯一性校验,所以对唯一索引进行更新时必须将对应的数据页加载到缓存中进行校验,从而导致ChangeBuffer失效。

普通索引还是唯一索引

通过以上分析,我们知道唯一索引无法使用ChangeBuffer,那么我们实际使用过程中应该使用普通索引还是唯一索引呢?

从等值查询性能角度来看

  • 普通索引在查找到第一个满足条件的数据之后,需要继续向后查找满足条件的数据;
  • 唯一索引在查找到第一个满足条件的数据之后,不需要再次向后查找,因为索引具有唯一性;

二者之间只相差一条记录,这个一条记录会带来多大的性能差距呢?答案是,微乎其微。因为InnoDB引擎是以页为单位读取数据的,读取一条数据时,往往会将临近的数据也读到内存,所以多向后查询几条数据带来的性能差别微乎其微。

从索引修改角度来看

由于非唯一索引无法使用ChangeBuffer,对索引的修改会引起大量的磁盘IO,影响数据库性能。

综上可知,如果不是业务中要求数据库对某个字段做唯一性检查,我们最好使用普通索引而不是唯一索引。

ChangeBuffer适用场景

什么情况下ChangeBuffer会有较大的性能提升呢?

  1. 数据库大部分索引是非唯一索引;
  2. 业务是写多读少,或者不是写后立刻读取;

不适合使用ChangeBuffer的场景与之对应:

先说什么时候不适合,如上文分析,当:

  1. 数据库都是唯一索引;
  2. 写入数据后,会立刻读取;

ChangeBuffer相关参数

  • innodb_change_buffer_max_size: 配置写缓冲的大小,占整个缓冲池的比例,默认值是25%,最大值是50%。
    写多读少的业务,才需要调大这个值。
  • innodb_change_buffering: 配置哪些写操作启用写缓冲,可以设置成all/none/inserts/deletes等。

我是御狐神,欢迎大家关注我的微信公众号:wzm2zsd

InnoDB学习(二)之ChangeBuffer

本文最先发布至微信公众号,版权所有,禁止转载!
点赞
收藏
评论区
推荐文章
3A网络 3A网络
2年前
从一条更新 SQL 的执行过程窥探 InnoDB 之 REDOLOG
从一条更新SQL的执行过程窥探InnoDB之REDOLOG1前言数据库为了取得更好的读写性能,InnoDB会将数据缓存在内存中(InnoDBBufferPool),对磁盘数据的修改也会落后于内存,这时如果进程或机器崩溃,会导致内存数据丢失,为了保证数据库本身的一致性和持久性,InnoDB维护了REDOLOG。修改Page之前需要
Wesley13 Wesley13
3年前
InnoDB存储引擎
InnoDB存储引擎InnodbBufferPool(缓存池)InnodbBufferPool的概念InnoDB的BufferPool主要用于缓存用户表和索引数据的数据页面。它是一块连续的内存,通过一定的算法对这块缓存做有效的管理。官方文档建议,如果此台服务器为MySQL专用数据库服务
Stella981 Stella981
3年前
InnoDB Buffer Pool巧配置全解
作者:M哥知数堂MySQL第8期学员、知数堂藏经阁项目星耀队队长一、简介InnoDB维护了一个缓存数据和索引信息到内存的存储区叫做BufferPool,它会将最近访问的数据缓存到缓冲区。我们通过配置各个BufferPool的参数,可以显著提高MySQL的性能。
Stella981 Stella981
3年前
Mybatis一二级缓存实现原理与使用指南
Mybatis与Hibernate一样,支持一二级缓存。一级缓存指的是Session级别的缓存,即在一个会话中多次执行同一条SQL语句并且参数相同,则后面的查询将不会发送到数据库,直接从Session缓存中获取。二级缓存,指的是SessionFactory级别的缓存,即不同的会话可以共享。缓存,通常涉及到缓存的写、读、过期(更新缓存
Stella981 Stella981
3年前
InnoDB脏页刷新机制Checkpoint
我们知道InnoDB采用WriteAheadLog策略来防止宕机数据丢失,即事务提交时,先写重做日志,再修改内存数据页,这样就产生了脏页。既然有重做日志保证数据持久性,查询时也可以直接从缓冲池页中取数据,那为什么还要刷新脏页到磁盘呢?如果重做日志可以无限增大,同时缓冲池足够大,能够缓存所有数据,那么是不需要将缓冲池中的脏页刷新到磁盘。但是,通常会有以下几
Wesley13 Wesley13
3年前
Mysql Innodb 引擎优化 参数(innodb_buffer_pool_size)
版权声明:本文为博主原创文章,未经博主允许不得转载。在mysql的学习过程中,要是不把一些基本概率弄的很清楚,难免显得过于不专业。作用:这个参数主要作用是缓存innodb表的索引,数据,插入数据时的缓冲默认值:128M专用mysql服务器设置的大小:操作系统内存的70%80%最佳。设置方法:my.cnf文件innodb\_
Stella981 Stella981
3年前
Hibernate(四)——缓存策略+lazy
Hibernate作为和数据库数据打交道的框架,自然会设计到操作数据的效率wenti,而对于一些频繁操作的数据,缓存策略就是提高其性能一种重要手段,而Hibernate框架是支持缓存的,而且支持一级和二级两种缓存,合理的使用缓存策略可以大大提高我们的操作数据效率,但是利用不能,可能会造成不必要的麻烦。一,一级缓存(Session缓
Stella981 Stella981
3年前
Redis 缓存穿透、缓存雪崩的概念及其预防
缓存穿透【什么是缓存穿透】频繁查询不在缓存中的数据,给原本被缓存保护的系统过大压力。【为什么会发生缓存穿透】1\.程序没写好;2\.恶意攻击。【怎样防止缓存穿透】1\.在对key进行查询之前,先做初步判断,如果key一定不存在(例如,对某表的缓存,key一定由数字组成,那么包含非数字的key一定是不存在的
Stella981 Stella981
3年前
Innodb Buffer Pool的三种Page和链表
一、InnodbBufferPool简介BufferPool是Innodb内存中的的一块占比较大的区域,用来缓存表和索引数据。众所周知,从内存访问会比从磁盘访问快很多。为了提高数据的读取速度,BufferPool会通过三种Page和链表来管理这些经常访问的数据,保证热数据不被置
贾蔷 贾蔷
1个月前
哈希表实现指南:从原理到C++实践
一、简介和应用哈希表(HashTable)是一种高效的数据结构,通过键值对(keyvalue)存储数据,提供快速的插入、删除和查找操作。它使用哈希函数将键映射到表中的位置,使得平均时间复杂度可以达到O(1)。‌应用场景‌:数据库索引、缓存实现(如Redis
贾蔷 贾蔷
4星期前
手把手教你实现哈希表:从代码到原理的新手友好指南
一、简介和应用哈希表(HashTable)是一种高效的数据结构,通过哈希函数将键(Key)映射到存储位置,实现O(1)时间复杂度的查找、插入和删除操作。它广泛应用于缓存系统、数据库索引、字典查询等场景。例如,在编程中需要快速根据用户ID查找信息时,哈希表能