Hexo

点滴积累 豁达处之

0%

Mysql插入缓存Insert buffer

InnoDB缓冲池中有Insert Buffer信息固然不错,但是InsertBuffer和数据页一样,也是物理页的一个组成部分。

什么是 innsert-buffer

插入缓冲是缓冲池中的一个组成部分。其实不然,InnoDB缓冲池中有Insert Buffer信息固然不错,但是InsertBuffer和数据页一样,也是物理页的一个组成部分

innsert-buffer作用

我们知道在进行插入操作时,数据页的存放还是按主键id的执行顺序存放, 但是对于非聚集索引,叶子节点的插入不再是顺序的了。
例如,对于如下表结构进行insert操作
create table tab (
id int auto_increment,
name varchar(30),
primary key (id),
key(name)
) engine=innodb default charset=utf8;
nanme 为非唯一字段,这时就需要离散地访问非聚集索引页,插入性能在这里变低了。然而这并不是这个name字段上索引的错误,因为B+树的特性决定了非聚集索引插入的离散性。
为了解决非聚族索引的随机写性能差(提升插入性能),InnoDB 存储引擎开发了 innsert-buffer pool (5.5 中做了加强,称之为 change buffer pool)

innsert-buffer 需要满足的条件

  • 索引是辅助索引(secondary index)
  • 索引不是唯一的(unique)

原因

1 主键是行唯一的标示符, 写入行时,是按照主键递增的顺序进行插入的,异常插入聚族索引一般也顺序的,不需要随机IO。
2 写唯一索引要检查记录是不是存在,所以在修改唯一索引之前,必须把修改的记录相关的索引页读出来才知道是不是唯一,这样Insert buffer就没意义了,反正要读出来(读带来随机IO),所以只对非唯一索引有效。

现实中的例子:

先说第一个问题。 我们去图书馆还书,对应图书馆来说,他是做了insert(增加)操作,管理员在1小时内接受了100本书,这时候他有2种做法把还回来的书归位到书架上

1)每还回来一本书,根据这本书的编码(书柜区-排-号)把书送回架上

2)暂时不做归位操作,先放到柜面上,等不忙的时候,再把这些书按照书柜区-排-号先排好,然后一次性归位

用方法1,管理员需要进出(IO)藏书区100次,不停的登高爬低完成图书归位操作,累死累活,效率很差。

用方法2,管理员只需要进出(IO)藏书区1次,对同一个位置的书,不管多少,都只要爬一次楼梯,大大减轻了管理员的工作量。

所以图书馆都是按照方法2来做还书动作的。但是你要说,我的图书馆就20本书,1个0.5米的架子,方法2和1管理起来都很方便,这种情况不在我们讨论的范围。当数据量非常小的时候,就不存在效率问题了。

关系数据库在处理插入操作的时候,处理的方法和上面类似,每一次插入都相当于还一本书,它也需要一个柜台来保存插入的数据,然后分类归档,在不忙的时候做批量的归位。这个柜台就是insert buffer.

我想这就是为什么会有insert buffer,更多的是处于性能优化的考虑。

再说第二个问题,有什么限制:“只对于非聚集索引(非唯一)的插入和更新有效”

为什么对于非聚集索引(非唯一)的插入和更新有效?

还是用还书的例子来说,还一本书A到图书馆,管理员要判断一下这本书是不是唯一的,他在柜台上是看不到的,必须爬到指定位置去确认,这个过程其实已经产生了一次IO操作,相当于没有节省任何操作。

所以这个buffer只能处理非唯一的插入,不要求判断是否唯一。聚集索引就不用说了,它肯定是唯一的,mysql现在还只能通过主键聚集。

原理

  • 先判断要更新的这一页在不在内存中。
  • 如果不在,则读取index page 存入Insert Buffer,按照Master Thread的调度规则来合并非唯一索引和索引页中的叶子结点.

Master Thread的调度规则

  • 主动merger[innodb主线程定期完成,用户线程无感知]
    主动merger:
    原理:主动merge通过innodb主线程(svr_master_thread)判断:若过去1s之内发生的I/O小于系统I/O能力的5%,
        则主动进行一次insert buffer的meger操作。meger的页面数为系统I/O能力的5%,读取采用async io模式。
        每10s,必定触发一次insert buffer meger操作。meger的页面数仍旧为系统 I/O能力的5%。
    步骤:
        1.主线程发出async io请求,async读取需要被meger的索引页面
        2.I/O handler 线程,在接受到完成的async I/O之后,进行merger
  • 被动merge[用户线程完成,用户能感受到meger操作带来的性能影响]
    被动merge:
      情况一:
      insert操作,导致页面空间不足,需要分裂(split)。由于insert buffer只针对单个页面,不能buffer page split[页已经在内存里],因此引起页面的被动meger。同理,update操作导致页面空间不 足;purge导致页面为空等。总之:若 当前操作引起页面split or merge,那么就会导致被动merge。
      情况二:
      insert操作,由于其它各种原因,insert buffer优化返回false,需要真正读取page时,要进行被动merge。与一不同的是,页在disk上,需要读取到内存里。
      情况三:
      在进行insert buffer操作,发现insert buffer太大,需要压缩insert buffer,这时需要强制被动merge,不允许 insert 操作进行。

如何查看insert buffer

我们可以通过show engine innodb status \G 来查看插入缓冲的信息

1
2
3
4
5
6
7
8
-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 2920 merges
merged operations:
insert 23858, delete mark 0, delete 0
discarded operations:
insert 0, delete mark 0, delete 0

seg size显示了当前插入缓冲的大小为2 *16KB,大约为32KB,free list len代表了空闲列表的长度,size代表了已经合并记录页的数量。merges 表示合并次数。
merged operations:
Inserts代表插入的记录数,delete mark delete 次数均为0.

参考链接