当前位置:Gxlcms > mysql > InnoDB关键特性之insertbuffer

InnoDB关键特性之insertbuffer

时间:2021-07-01 10:21:17 帮助过:41人阅读

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 的设计意义。

插入缓冲带来的问题

任何一项技术在带来好处的同时,必然也带来坏处。插入缓冲主要带来如下两个坏处:

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

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

插入缓冲的内部实现

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

人气教程排行