• InnoDB关键特性之insert buffer


    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表示都不启用。

     

  • 相关阅读:
    20155220 吴思其 《网络攻防》 Exp1 PC平台逆向破解(5)M
    20155220 《信息安全系统设计基础》课程总结
    2017-2018-1 20155220 《信息安全系统设计基础》第十四周学习总结
    2017-2018-1 20155220 《信息安全系统设计基础》第十三周学习总结
    2017-2018-1 20155220 实验五 通讯协议设计
    2017-2018-1 20155220实验四——外设驱动程序设计
    20155220 《信息安全系统设计基础》第11周学习总结
    《信息安全技术》实验四 木马及远程控制技术
    2017-2018-1 20155220 《信息安全系统设计基础》课下实践——实现mypwd
    2017-2018-1 20155220 实验三 实时系统
  • 原文地址:https://www.cnblogs.com/yuyue2014/p/3802779.html
Copyright © 2020-2023  润新知