ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

MySQL提升插入效率大杀器 — Change Buffer

2021-07-06 12:59:32  阅读:361  来源: 互联网

标签:Insert 插入 Buffer Merge 索引 大杀器 MySQL Change


目录

为何慢

Change Buffer

​处理流程

Insert

Delete

Update

内部实现

B+树

Insert Buffer Bitmap

Merge处理

辅助索引被读取

辅助索引页已无可用空间

Master Thread 定时 Merge

相关配置

innodb_change_buffer_max_size

innodb_change_buffering

适用场景


为何慢

       大家在面试中应该都会遇到这样一个问题:索引建多了有什么坏处?相信大家都能很快地答出来会造成插入和更新数据变慢,有没有想过原因究竟是为什么呢?

       我们都知道在 InnoDB 存储引擎中,主键是行唯一的标识符,通常行记录的插入顺序是按照主键递增的顺序进行插入的,因此,插入聚簇索引一般是顺序的,不需要磁盘的随机读取。

注意,并不是所有的主键插入都是顺序的,如果主键是类似 UUID 这样的规则,插入和辅助索引一样,同样是随机的。 

        当我们创建辅助索引(非聚簇索引)时,叶子节点的插入不再是顺序的了,这是就需要随机地访问非聚簇索引页,由于随机 IO 的存在而导致了插入操作性能下降。

        那么 InnoDB 是如何解决这个问题的呢?

Change Buffer

       InnoDB 存储引擎可以对 DML 操作 —— INSERT、DELETE、UPDATE 操作进行缓冲,分别对应 Insert Buffer、Delete Buffer、Purge Buffer,所以 Change Buffer 其实是三者的总称。

        Change Buffer 是一种特殊的数据结构,用于在对数据变更时,如果数据所在的数据页没有在 Buffer Pool 中的话,InnoDB 引擎会将对数据的操作缓存在 Change Buffer 对象中,这样就省去了从磁盘中读入这个数据页。将数据页从磁盘读入内存中涉及随机 IO 访问,这也是数据库里面成本最高的操作之一,而利用写缓存(Change Buffer)可以减少 IO 操作,从而提升数据库性能。 InnoDB 的技术架构图如下:

InnoDB 架构图

       Change Buffer 是 Buffer Pool 中的一部分,虽然 Change Buffer 名字叫 Buffer ,但是它也是可以持久化的,在右边的 System Tablespace 中可以看到持久化 Change Buffer 的空间。Change Buffer 中的数据最终还是会刷回到数据所在的原始数据页中,Change Buffer 数据应用到原始数据页,得到新的数据页的过程称之为 Merge。Merge 过程中只会将 Change Buffer 中与原始数据页有关的数据刷到原始数据页。

Change Buffer 的架构图处理流程

        下面分别对 Insert、Delete、Update 分别介绍。

Insert

  1. 判断是否是聚簇索引,如果是,直接写入索引页,不执行后续操作。
  2. 索引是否在 Change Buffer 中,如果在则直接插入到索引页中;若不在,则写入 Change Buffer 对象中。
  3. 某些操作触发 Merge,将同一个索引页的多个插入合并到同一个操作中。

Delete

  1. 将记录标记为已删除,放入 Purge Buffer 中。
  2. 某些操作触发 Merge,进行 Purge 操作并删除。

Update

       Update 本质上是先进行 Delete,再 Insert,所以是上面两个流程的结合,就不再赘述了。

内部实现

       通过上面的流程我们发现,其实真正往 Change Buffer 写入数据只发生在 Insert Buffer 中,索引我们着重介绍 Insert Buffer 的内部实现。

B+树

       Insert Buffer 是一颗 B+ 树,因此其也由叶子节点和非叶子节点组成。

       非叶子节点存储查询的 search key,一共占9个字节,space 占4个字节,存储每个表的唯一 space id,marker 占1个字节用于兼容老版本,offset 占4个字节,表示对应页所在的偏移量,结构如下图所示。

      对于插入到 Insert Buffer B+ 树叶子节点的记录,需要根据如下规则进行构造:space、marker、offset 字段和非叶子节点含义相同,第4个字端 metadata 占4个字节,存储 Insert Buffer 中记录的插入顺序等信息。

Insert Buffer Bitmap

       为了保证每次 Merge Insert Buffer 不许成功,需要有一个特殊的页用来标记每个辅助索引的可用空间,这个页的类型为 Insert Buffer Bitmap。每个 Bitmap 页用来追中 16384 个辅助索引页,每个索引占 4 位,结构如下:

名称大小(bit)说明
IBUF_BITMAP_FREE2

表示该服辅助索引页中的可用空间数量:

0-无可用剩余空间

1-剩余空间大于1/32页

2-剩余空间大于1/16页

3-剩余空间大于1/8页

IBUF_BITMAP_BUFFERED11表示该辅助索引页有记录被缓存在 Insert Buffer B+ 树中
IBUF_BITMAP_IBUF11表示该页为 Insert Buffer B+ 树的非叶子节点

Merge处理

Merge 操作可能发生在以下几种情况:

  • 辅助索引被读取时。
  • Insert Buffer Bitmap 页追踪到该辅助索引页已无可用空间时。
  • Master Thread 定时 Merge。

辅助索引被读取

       当辅助索引页被读取到缓冲池(select)时,需要检查 Insert Buffer Bitmap 页,确认该服务索引页是否有记录存在于 Insert Buffer B+ 树中,若有则将 Insert Buffer B+ 树中该页的记录批量插入到该辅助索引页中。

辅助索引页已无可用空间

       若插入辅助索引记录时检测到插入记录后可用空间会小于 1/32 页,则会强制进行一次 Merge 操作,将 Insert Buffer B+ 树中该页的记录插入到辅助索引页中。

Master Thread 定时 Merge

       Master Thread 线程中会每隔一定时间,根据 srv_innodb_io_capactiy 的百分比进行一次 Merge Insert Buffer 操作。

相关配置

上面就是写缓存(Change Buffer)的相关知识,写缓存(Change Buffer)我们也是可以使用命令参数来控制,MySQL 数据库提供了两个对写缓存(Change Buffer)的参数。
Change Buffer 参数

innodb_change_buffer_max_size

innodb_change_buffer_max_size 表示 Change Buffer 最大大小占 Buffer Pool 的百分比,默认为 25%。最大可以设置为 50%。

innodb_change_buffering

innodb_change_buffering 参数用来控制对哪些操作启用 Change Buffer 功能,默认是:all。innodb_change_buffering 参数有以下几种选择:

  • --all: 默认值。开启buffer inserts、delete-marking operations、purges

  • --none: 不开启change buffer

  • --inserts: 只是开启buffer insert操作

  • --deletes: 只是开delete-marking操作

  • --changes: 开启buffer insert操作和delete-marking操作

  • --purges: 对只是在后台执行的物理删除操作开启buffer功能

对上面写缓存(Change Buffer)如果你还是云里雾里的话,那么我们就用一个案例来说明一下 Change Buffer ,首先我们向数据库中插入两条数据:

mysql> insert into t(id,k) values(id1,k1),(id2,k2);

结合下面这张图来分析这两条插入语句。

图片来源极客时间

假设当前是 K索引树的状态,K1 所在的数据页 page1 在 Buffer Pool 中,k2 所在的数据页不在 Buffer Pool 中,来看看这两条语句的执行流程:

1、对于 k1 这条数据,Page 1 在内存中,所以直接更新内存,不会使用到 Change Buffer;

2、k2 对应的数据页 Page 2 没有在内存中,就在内存的 change buffer 区域,记录下“我要往 Page 2 插入一行”这个信息,这个地方及其关键,并没有从磁盘中将 page2 加载到内存。

3、将上述两个动作记入 redo log 中(图中 3 和 4)。

4、后台线程会定时将 page1 和 Change Buffer 中的数据持久化

主要地方在于步骤二,这就是写缓存(Change Buffer)提高性能的地方,虽然 page2 并没有在内存中,但是并没有妨碍我们往数据库 page2 中插入数据,这就是写缓存(Change Buffer)的巧妙之处,也是写缓存(Change Buffer)提高 MySQL
的地方。

适用场景

       Change Buffer 并不是适用于所有场景,如果你的应用是以下场景之一,则不适合开启。

       数据库都是唯一索引:如果数据库都是唯一索引,那么在每次操作的时候都需要判断索引是否有冲突,势必要将数据加载到缓存中对比,因此也用不到 Change Buffer。

       写入一个数据后,会立刻读取它:写入一个数据后,会立刻读取它,那么即使满足了条件,将更新先记录在 change buffer,但之后由于马上要访问这个数据页,会立即触发 merge 过程。这样随机访问 IO 的次数不会减少,反而增加了 change buffer 的维护代价。所以,对于这种业务模式来说,change buffer 反而起到了副作用。

以下几种情况开启 Change Buffer,会使得 MySQL 数据库明显提升:

  • 数据库大部分是非唯一索引
  • 业务是写多读少
  • 写入数据之后并不会立即读取它

标签:Insert,插入,Buffer,Merge,索引,大杀器,MySQL,Change
来源: https://blog.csdn.net/why444216978/article/details/118516576

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有