MySQL Innodb关键特性之插入缓冲(insert buffer)


Posted in MySQL onApril 08, 2021

什么是insert buffer?

   插入缓冲,也称之为insert buffer,它是innodb存储引擎的关键特性之一,我们经常会理解插入缓冲时缓冲池的一个部分,这样的理解是片面的,insert buffer的信息一部分在内存中,另外一部分像数据页一样,存在于物理页中。

    在innodb中,我们知道,如果一个表有自增主键,那么对于这个表的默认插入是非常快的,注意,这里的主键是自增的,如果不是自增的,那么这个插入将会变成随机的,就可能带来数据页分裂的开销,这样,插入就不是顺序的,就会变慢。还有一种情况,就是如果我们插入的id不是顺序的,而是随机的,那么即使有自增主键,那么插入的速度也不会特别快。

    如果我们定义了一个表,包含一个主键和一个非聚集索引,如下:

create table t(

a int auto_increment,

b varchar(30),

primary key(a),

key (b)

);

当我们按照主键a进行插入的时候,对于非聚集索引,也就是常说的二级索引b,它的插入不是顺序的,插入性能必然会下降。

  Innodb存储引擎针对这种情况,设计了Insert Buffer,对于非聚集索引的插入或者更新操作,不是每一次插入到索引页中,而是先判断插入的非聚集索引页是否在缓冲池中,如果在,则直接插入,如果不在,则先放入一个insert buffer中,告诉数据库这个非聚集的索引已经插入到了叶子节点,实际上并没有插入,只是存放在另外一个位置,然后再以一定的频率和情况进行Insert buffer和辅助索引叶子节点合并操作。这种时候,经常能将多条记录的插入合并到一个操作中,这样就大大提高了非聚集索引离散插入的性能。

insert buffer的触发条件?

    insert buffer需要满足两个条件才能被使用,第一,索引是辅助索引,也就是二级索引,第二,索引不是唯一的。当满足上述两个条件的时候,就可以使用insert buffer,从而提高数据库的插入操作性能。

    这里需要注意,如果在程序进行了大量操作的时候发生了MySQL数据库的宕机,那么肯定有大量的insert buffer没有合并到实际的非聚集索引中去,恢复可能会造成很长的时间。

为什么不能是唯一索引?

    之所以不支持唯一索引,是因为如果辅助索引是唯一索引,那么在插入时需要校验唯一性,校验唯一性的时候就会发生离散读取,从而又增加了开销,那么insert buffer得不偿失。

    我们可以通过show engine innodb status来查看insert buffer的使用情况,如下:

mysql--root@localhost:dms_alimetadata 20:35:24>>show engine innodb status\G
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0

  其中size代表了已经合并记录页的数量,free list len代表了空闲列表的长度,seg size显示了当前insert buffer的大小为2*16KB

引入Change Buffer的概念

    最新的MySQL5.7已经支持change buffer,事实上,它在innodb 1.0.x版本已经引入,这个change buffer 可以理解为insert buffer的升级,也就是对常见的DML语言都可以进行缓冲,包含insert delete以及update,对应的分别是insert buffer,delete buffer以及purge buffer。

   当然,change buffer的使用对象仍然是非唯一的辅助索引。

    这里我们以update操作为例,update的过程可以拆分为两个部分:

第一个部分是将记录的delete_mask标记为删除,如果你不了解delete_mask,可以在4月9号的文章中去看。第二个部分是真正的将记录删除。

而delete buffer对应的是update的第一个过程,purge buffer对应的是第二个部分。

    在innodb中,我们可以通过参数innodb_change_buffering来开启buffer的各种选项,该参数可选的值为inserts,deletes,purges,changes,all,none等,其中inserts,deletes和purges就是前面讨论过的情况,changes表示开启inserts和deletes,all表示开启所有,默认的参数如下:

mysql--root@localhost:dms_alimetadata 21:13:37>>show variables like '%buffering%';        
+-------------------------+-------+
| Variable_name           | Value |
+-------------------------+-------+
| innodb_change_buffering | all   |
+-------------------------+-------+
1 row in set (0.01 sec)

我们还可以通过innodb_change_buffer_max_size来控制change_buffer的最大使用内存数量,该参数的默认值是25,也就是1/4,示例如下:

mysql--root@localhost:dms_alimetadata 21:20:52>>show variables like '%innodb_change_buffer_max_size%';
+-------------------------------+-------+
| Variable_name                 | Value |
+-------------------------------+-------+
| innodb_change_buffer_max_size | 25    |
+-------------------------------+-------+
1 row in set (0.00 sec)

    在上面的show engine innodb status命令的输出结果中,显示了merged operation和discarded operation,其中insert 表示insert buffer的操作次数,delete mark表示delete buffer的操作次数,而delete表示purge buffer的操作次数,discarded operation表示当change buffer发生merge时,表已经被删除,此时就无需进行合并。

Insert Buffer的实现?

   insert buffer的数据结构是一棵B+树,类似聚集索引一样,全局只有一棵insert buffer B+树,它负责对所有的表进行insert buffer,而这棵B+树放在共享表空间中,也就是ibdata1文件中,因此,试图通过ibd文件恢复表数据的时候可能会出现check table失败,原因是表的辅助索引中的数据可能还在insert buffer中,所以通过ibd文件恢复文件之后,还需要进行repair table操作来重建表上的辅助索引。

   insert buffer既然是一棵树,那么必定有叶子节点和非叶子节点,非叶子节点存放的是查询的search key值,它的构造如下:

+---------+------------+-------+
| space   |   marker   | Value |
+---------+------------+-------+

这个结构一共占用9个字节,其中,space表示待插入的记录所在的表的表空间id,这个id是每个表都要有的唯一的id,其中space占用4个字节,marker占用1个字节,用来兼容老版本的insert buffer,offset占用4个字节,表示页所在的偏移量。

辅助索引的插入过程?

    当一个辅助索引要插入到数据页的时候,如果这个数据页不在缓冲池中,那么innodb会根据规则构造一个search key,接下来将这个记录插入到insert buffer的B+树里面去,插入的过程中,需要对这个记录进行一些构造,最终插入的结果是类似下面这样的一条记录:

+---------+------------+-------+------------+------+-------+------+-------+
| space   |   marker   | Value | metadata   |      |       |      |       |
+---------+------------+-------+------------+------+-------+------+-------+

可以发现,最后面多了一个metadata的字段和4个其他的字段,先来说说metadata的字段,它占用4个字节,它用来排序每个记录进入insert buffer的顺序,从第5列开始,就是实际插入记录的各个字段的值了,因此和单纯的数据记录相比,insert buffer需要额外13个字节的开销。

   为了保证每次merge insert buffer成功,需要设置一个特殊的数据页来标记每个辅助索引页的可用空间,这个数据页的类型为insert buffer bitmap,这个页可以追踪很多辅助索引页的可用空间。这里简单了解一下,下面会解释它的用法。

Merged Insert Buffer的时机?

   我们前面已经知道,当插入记录的辅助索引页不在缓冲池中的时候,需要将辅助索引记录插入到这棵B+树中,后续会从insert buffer中往真正的辅助索引中进行合并,那么什么时候进行合并呢?

1、辅助索引页被读取到缓冲池的时候

2、insert buffer Bitmap追踪到该辅助索引页已经没有足够的可用空间时,一般的阈值是辅助索引页空间的1/32

3、master thread每秒执行一次merge insert buffer的操作

以上就是MySQL Innodb关键特性之插入缓冲(insert buffer)的详细内容,更多关于Innodb特性之插入缓冲的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
MySQL 全文索引使用指南
May 25 MySQL
Unity连接MySQL并读取表格数据的实现代码
Jun 20 MySQL
mysql备份策略的实现(全量备份+增量备份)
Jul 07 MySQL
MySQL 5.7常见数据类型
Jul 15 MySQL
MySQL 用 limit 为什么会影响性能
Sep 15 MySQL
MySQL中datetime时间字段的四舍五入操作
Oct 05 MySQL
SpringBoot连接MySQL获取数据写后端接口的操作方法
Nov 02 MySQL
浅谈如何保证Mysql主从一致
Mar 13 MySQL
mysql中DCL常用的用户和权限控制
Mar 31 MySQL
解决MySQL Varchar 类型尾部空格的问题
Apr 06 MySQL
MySQL时区造成时差问题
Apr 13 MySQL
MySQL数据库 任意ip连接方法
May 20 MySQL
如何使用Maxwell实时同步mysql数据
MySQL创建索引需要了解的
Apr 08 #MySQL
MySQL 使用SQL语句修改表名的实现
详解Mysql 函数调用优化
Apr 07 #MySQL
MySQL复制问题的三个参数分析
Apr 07 #MySQL
MySQL pt-slave-restart工具的使用简介
Apr 07 #MySQL
MySQL主从复制断开的常用修复方法
Apr 07 #MySQL
You might like
mysql 中InnoDB和MyISAM的区别分析小结
2008/04/15 PHP
浅析PHP程序设计中的MVC编程思想
2014/07/28 PHP
asp函数split()对应php函数explode()
2019/02/27 PHP
js图片向右一张张滚动效果实例代码
2013/11/23 Javascript
JavaScript 32位整型无符号操作示例
2013/12/08 Javascript
JS实现从网页顶部掉下弹出层效果的方法
2015/08/06 Javascript
Javascript生成带参数的二维码示例
2016/10/10 Javascript
js实现可输入可选择的select下拉框
2016/12/21 Javascript
使用重写url机制实现验证码换一张功能
2017/08/01 Javascript
angularjs实现猜数字大小功能
2020/05/20 Javascript
vue-router命名视图的使用讲解
2019/01/19 Javascript
Element-UI中Upload上传文件前端缓存处理示例
2019/02/21 Javascript
微信小程序登录时如何获取input框中的内容
2019/12/04 Javascript
[42:06]2019国际邀请赛全明星赛 8.23
2019/09/05 DOTA
linux系统使用python监测网络接口获取网络的输入输出
2014/01/15 Python
Python使用py2exe打包程序介绍
2014/11/20 Python
Python实现登录人人网并抓取新鲜事的方法
2015/05/11 Python
python实现的简单RPG游戏流程实例
2015/06/28 Python
Python的组合模式与责任链模式编程示例
2016/02/02 Python
python使用 HTMLTestRunner.py生成测试报告
2017/10/20 Python
解决pip install的时候报错timed out的问题
2018/06/12 Python
Python IDLE清空窗口的实例
2018/06/25 Python
python实现ssh及sftp功能(实例代码)
2020/03/16 Python
python如何查看网页代码
2020/06/07 Python
收藏!10个免费高清视频素材网站!【设计、视频剪辑必备】
2021/03/18 杂记
如何开发安全的AJAX应用
2014/03/26 面试题
《最可爱的人》教学反思
2014/02/14 职场文书
铲车司机岗位职责
2014/03/15 职场文书
毕业自我鉴定怎么写
2014/03/25 职场文书
小班评语大全
2014/05/04 职场文书
领导干部廉政自律承诺书
2014/05/26 职场文书
2014党员学习兰辉先进事迹思想汇报
2014/09/17 职场文书
干部年终考核评语
2015/01/04 职场文书
财务总监岗位职责
2015/02/03 职场文书
西安大雁塔导游词
2015/02/10 职场文书
敬老院志愿者活动总结
2015/05/06 职场文书