insert buffer 是InnoDB存储引擎所独有的功能。通过insert buffer,InnoDB存储引擎可以大幅度提高数据库中非唯一辅助索引的插入性能。

数据库对于自增主键值的插入是顺序的,因此插入能有较高的性能。但是实际生产环境中,用户表中主键仅有并且只能有1个,然而表中可能存在多个辅助索引。

为了阐述非聚集索引写性能问题,我们先来看一个例子:

mysql>create table t (
           id int auto_increment,
           name varchar(30),
           primary key (id));

我们创建了一个表,表的主键是id,id列式自增长的,即当执行插入操作时,id列会自动增长,页中行记录按id顺序存放,不需要随机读取其它页的数据。因此,在这样的情况下(即聚集索引),插入操作效率很高。

对于上一张表t,业务上还需要按非唯一的name字段查找,则表定义改为:

mysql>create table t (
           id int auto_increment,
           name varchar(30),
           primary key (id),
           key (name));

这时,除了主键聚合索引外,还产生了一个name列的辅助索引,对于该非聚集索引来说,叶子节点的插入不再有序,这时就需要离散访问非聚集索引页,插入性能变低。

插入缓冲原理

为了解决这个问题,InnoDB设计出了插入缓冲技术,对于非聚集类索引的插入和更新操作,不是每一次都直接插入到索引页中,而是先判断插入的非聚集索引叶子是否在缓冲池中,若在,则直接插入;若不在,则先将插入的记录放到insert buffer中,然后根据一些算法将insert buffer 缓存的记录通过后台线程慢慢的合并(merge)回辅助索引页中。这样做的好处是:(1)减少磁盘的离散读取;(2)将多次插入合并为一次操作。

例如name字段的插入顺序为:

('Maria',10), ('David',7), ('Tim', 11), ('Jim', 7), ('Monty', 10), ('Herry', 7), ('Heikki', 7)

后面的数字表示原先插入的辅助索引的page_no,可以看到页的访问是完全无序的,然而当插入到insert buffer中时,上述记录可能在一个页中,因此减少了离散读取。在insert buffer中,记录根据应插入辅助索引的叶子节点page_no进行排序,故上述记录在insert buffer中的状态应为:

('David',7), ('Jim', 7), ('Herry', 7), ('Heikki', 7) , ('Maria',10), ('Monty', 10), ('Tim', 11)

当要进行合并时,页page_no为7的记录有4条,可以一次性将这4条记录插入到辅助索引中,从而提高数据库的整体性能。

insert buffer的使用需要满足以下两个条件:

(1)索引是辅助索引(secondary index)

(2)索引是非唯一的

若是唯一索引,那么在插入时需要判断插入的记录是否是唯一,这需要读取辅助索引页,而insert buffer 的设计就是避免读取insert buffer,这会导致失去insert buffer 的设计意义。

插入缓冲的内部实现

insert buffer的数据结构是一棵B+树。在MySQL4.1之前的版本中每张表都有一棵insert buffer B+树。而在现在的版本中,全局只有一棵insert buffer B+树,负责对所有的表的辅助索引进行 insert buffer。这棵B+树存放在共享表空间中,默认也就是ibdata1中。因此,试图通过独立表空间ibd文件恢复表中数据时,往往会导致check table 失败。这是因为表的辅助索引中的数据可能还在insert buffer中,也就是共享表空间中。所以通过idb文件进行恢复后,还需要进行repair table 操作来重建表上所有的辅助索引。

insert buffer是一棵B+树,因此其也由叶子节点和非叶子节点组成。非叶子节点存放的是查询的search key(键值)。其构造包括三个字段:space | marker | offset。

search key一共占9字节,其中space占4字节,marker占1字节、offset占4字节。space表示待插入记录所在的表空间id,在InnoDB存储引擎中,每个表有一个唯一的space id,可以通过space id查询得知是哪张表。marker是用来兼容老版本的insert buffer。offset表示页所在的偏移量。

当一个辅助索引需要插入到页(space, offset)时,如果这个页不在缓冲池中,那么InnoDB存储引擎首先根据上述规则构造一个search key,接下来查询insert buffer这棵B+树,然后再将这条记录插入到insert buffer B+树的叶子节点中。

对于插入到insert buffer B+树叶子节点的记录,需要根据如下规则进行构造:

space | marker | offset | metadata | secondary index record

启用insert buffer索引后,辅助索引页(space、page_no)中的记录可能被插入到insert buffer B+树中,所以为了保证每次merge insert buffer页必须成功,还需要有一个特殊的页来标记每个辅助索引页(space、page_no)的可用空间。这个页的类型为insert buffer bitmap。

概括的说,merge insert buffer的操作可能发生在以下几种情况:

(1)辅助索引页被读取到缓冲池时;

(2)insert buffer bitmap页追踪到该辅助索引页已无可用空间时;

(3)master thread。

插入缓冲带来的问题

插入缓冲主要带来如下两个坏处:

(1)可能导致数据库宕机后实例恢复时间变长。如果应用程序执行大量的插入和更新操作,且涉及非唯一的聚集索引,一旦出现宕机,这时就有大量内存中的插入缓冲区数据没有合并至索引页中,导致实例恢复时间会很长。

(2)在写密集的情况下,插入缓冲会占用过多的缓冲池内存(innodb_buffer_pool),默认情况下最大可以占用1/2,这在实际应用中会带来一定的问题。

插入缓冲的升级:change buffer

InnoDB从1.0.x版本开始引入了change buffer,可以将其视为insert buffer的升级。从这个版本开始,InnoDB存储引擎可以对DML操作——insert、delete、update都进行缓冲,它们分别是:insert buffer、delete buffer、purge buffer。

和insert buffer一样,change buffer适用的对象依然是非唯一的辅助索引。

对一条记录进行update操作可以分为两个过程:

(1)将记录标记为删除;

(2)真正将记录删除。

因此delete buffer对应update操作的第一个过程,即将记录标记为删除。purge buffer对应update操作的第二个过程,即将记录真正的删除。同时InnoDB存储引擎提供了参数innodb_change_buffering,用来开启各种buffer选项。该参数的可选值为:inserts、deletes、purges、changes、all、none。inserts、deletes、purges就是前面讨论过的三种情况。changes表示启用inserts和deletes,all表示启用所有,none表示都不启用。

InnoDB关键特性之insert buffer的更多相关文章

  1. innodb 关键特性(insert buffer)

    一.insert buffer 性能改善 insert buffer和数据页一样,也是物理页的一个组成部分. 在innodb存储引擎中,主键是行唯一的标识符.通常应用程序中行记录的插入顺序是按照主键递 ...

  2. InnoDB关键特性之change buffer

    一.关于IOT:索引组织表 表在存储的时候按照主键排序进行存储,同时在主键上建立一棵树,这样就形成了一个索引组织表,一个表的存储方式以索引的方式来组织存储的. 所以,MySQL表一定要加上主键,通过主 ...

  3. 【mysql】Innodb三大特性之insert buffer

    一.什么是insert buffer insert buffer是一种特殊的数据结构(B+ tree)并不是缓存的一部分,而是物理页,当受影响的索引页不在buffer pool时缓存 secondar ...

  4. InnoDB关键特性学习笔记

    插入缓存 Insert Buffer Insert Buffer是InnoDB存储引擎关键特性中最令人激动与兴奋的一个功能.不过这个名字可能会让人认为插入缓冲是缓冲池中的一个组成部分.其实不然,Inn ...

  5. innodb关键特性之double write

    # 脏页刷盘的风险 两次写的原理机制 1.解决问题 2.使用场景 3.doublewrite的工作流程 4.崩溃恢复 # doublewrite的副作用 1.监控doublewrite负载 2.关闭d ...

  6. my36_InnoDB关键特性之change buffer

    一.关于IOT:索引组织表 表在存储的时候按照主键排序进行存储,同时在主键上建立一棵树,这样就形成了一个索引组织表,一个表的存储方式以索引的方式来组织存储的. 所以,MySQL表一定要加上主键,通过主 ...

  7. InnoDB关键特性之刷新邻接页-异步IO

    Flush neighbor page 1.工作原理 2.参数控制 AIO 1.开启异步IO 一.刷新邻接页功能 1.工作原理 当刷新一个脏页时,innodb存储引擎会检测该页所在区(extent)的 ...

  8. InnoDB关键特性之自适应hash索引

    一.索引的资源消耗分析 1.索引三大特点 1.小:只在一个到多个列建立索引 2.有序:可以快速定位终点 3.有棵树:可以定位起点,树高一般小于等于3 2.索引的资源消耗点 1.树的高度,顺序访问索引的 ...

  9. innodb 关键特性(两次写与自适应哈希索引)

    两次写: 场景: 当发生数据库宕机时,可能innodb存储引擎正在写入某个页到表中,而这个页只写了一部分,这种情况被称为部分写失效,如果发生,可以通过重做日志进行恢复,重做日志中记录的是对页的物理操作 ...

随机推荐

  1. 【IOCP】 IOCP模型属于一种通讯模型- 较难

    http://baike.baidu.com/link?url=e9vXkKd2aHp8VDr1XTURdwQB4K85r28IYjeMwRIyuaXtsrCsXHY1eohiFgsDXRYRlj6x ...

  2. EXTJS 4.2 资料 控件之Window窗体自动填充页面

    1.html页面代码: <div id="component" style="width:100%;height:100%"> <body&g ...

  3. 【BZOJ3196】Tyvj 1730 二逼平衡树

    Description 您需要写一种数据结构(可参考题目标题),来维护一个有序数列,其中需要提供以下操作:1.查询k在区间内的排名2.查询区间内排名为k的值3.修改某一位值上的数值4.查询k在区间内的 ...

  4. python学习笔记19(序列的方法)

    序列包含有宝值 表(tuple)和表(list).此外,字符串(string)是一种特殊的定值表,表的元素可以更改,定值表一旦建立,其元素不可更改. 任何的序列都可以引用其中的元素(item). 下面 ...

  5. iOS的view翻转动画实现--代码老,供参考

    新建一个view-based模板工程,在ViewController文件中添加下面的代码,即可实现翻转效果: - (void)viewDidLoad { [super viewDidLoad]; // ...

  6. js 人工获取年月日

    var date = new Date(); var months = new Array("01", "02", "03", " ...

  7. [转载]mvc使用JsonResult返回Json数据

    controller 中定义以下方法: public JsonResult UpdateSingle(int id, string actionName, string actionValue) { ...

  8. POJ1260Pearls

    http://poj.org/problem?id=1260 题意 :这个题大概是讲,给你几种等级不同的珠宝,然后告诉你它的数量和价值,等级是升序排列的,且随等级的升高价值也随之升高,但为了防止有的客 ...

  9. hdu 2509 Be the Winner 博弈论

    博弈论水题!!! 代码如下: #include<stdio.h> #include<iostream> using namespace std; int main(){ int ...

  10. Nginx的介绍和使用

    http://blog.csdn.net/shimiso/article/details/8690897 1.什么是Nginx Nginx(发音同 engine x)是一款轻量级的Web 服务器/反向 ...