要想深刻的理解InnoDB插入缓冲特性,我们需要对mysql的索引有比较深刻的理解。
聚集索引和非聚集索引
聚集索引:聚集索引是指数据库表行中数据的物理顺序与键值的逻辑(索引)顺序相同。
在InnoDB中,表中的数据都是按照主键顺序存放。而聚集索引就是按照每张表的主键构造一棵B+树,同时叶子节点中存放的就是整张表的行记录数据,也将聚集索引的叶子节点称为数据页。同B+树结构一样,每隔数据页都通过一个双向链表进行链接。
由于实际的数据结构只能按照一棵B+树进行排序,因此每张表只能拥有一个聚集索引。
我觉得下面这张图还是很形象的表达出了B+树的结构以及聚集索引。。。。
又找了一组图:聚集索引,叶子节点上索引和数据是在一起的,找到索引也就找到了数据。
非聚集索引:该索引中索引的逻辑顺序与磁盘上行的物理存储顺序不同,也称为辅助索引。
对于辅助索引,叶子节点并不包含行记录的全部数据,叶子节点除了包含键值(辅助索引的键值)以外,每个叶子节点中的索引行中还包含了一个书签,该书签用来高速InnoDB存储引擎哪里可以找到与索引相对应的行数据(其实就是主键索引),通过主键索引再去找到具体的行数据。
插入性能
在InnoDB存储引擎中,主键是行唯一的标识符。通常应用程序中行记录的插入顺序是按照主键递增的顺序进行插入的。因此,插入聚集索引一般是顺序的,不需要磁盘的随机读取,因此速度是非常快的
当然主键仅限于自增型,如果是UUID这种本身没有顺序性,插入时跟辅助索引一样,效率也会很低。
为什么辅助索引插入效率低呢?
CREATE TABLE t(
a INT AUTO_INCREMENT,
b VARCHAR(30),
PRIMARY KEY(a),
key(b)
);
如表 t 中对 b 建立一个辅助索引。当我们向表中插入一条数据时,因为表中的数据是按照主键a的顺序排序的,但是对于非聚集索引b的叶子节点的插入不再是顺序的了,这时就需要离散的访问非聚集索引页,离散的访问非聚集索引页导致性能下降。
为什么需要访问非聚集索引页呢?
因为非聚集索引也是需要排序的,每次插入新的数据,不仅要按照主键进行排序,同时也需要将数据按照非聚集索引在非聚集索引页中进行索引排序。在非聚集索引页中找到辅助索引所在的位置进行插入,这样由于随机读取的存在会导致插入操作性能下降。
插入缓冲技术(Insert Buffer)
Insert Buffer需要满足两个条件:
- 索引是辅助索引
- 索引不是唯一的。
如果索引是唯一索引的话,在插入时,还需要去查找索引页中来判断记录的唯一性,这样又会有离散读取索引页的情况发生,从而导致了Insert Buffer失去了意义。
当同时满足以上两个条件时,InnoDB存储引擎才会使用Insert Buffer。
Insert Buffer 实现:
Insert Buffer是一棵B+树,因此他也分为非叶子节点和叶子节点两部分。
非叶子节点存放的是查询的search key值,结构如图:
|space| marker | offset |
search key一共占用9个字节,space表示待插入记录所在表的表空间id,在InnoDB存储引擎中,每个表有一个唯一的space id,可以通过space id查询得知是哪张表,space占用4字节,marker是用来兼容老版本的Insert Buffer,占用1字节,offset则表示页所在的偏移量,占用4字节。
而对于叶子节点的结构如下图:
| space | marker | offset | metadata | …| … | …| …|
前面字段含义和空间和非叶子节点相同,metadata字段用来记录一些额外信息,例如插入记录的顺序等,从第5列开始,就是实际插入记录的各个字段了。
当一个辅助索引要插入到页(space,offset)时,如果这个也不在缓冲池中,那么InnoDB存储引擎首先根据上述规则构造一个search key,接下来查询Insert Buffer这棵B+树,然后将这条记录插入到Insert Buffer B+树的叶子节点中。
当记录插入到Insert Buffer B+树中后,真正将记录合并到数据库表记录是通过merge Insert Buffer进行的(j将多个插入操作合并成一个执行)。为了保证每次Merge Insert Buffer成功执行,还需要有一个特殊的页用来标记每个辅助索引页(space,page_no)的可用空间。这个页的类型为Insert Buffer Bitmap.
发生MergeBuffer的几种情况:
- 辅助索引页被读取到缓冲池时
- Insert Buffer Bitmap页追踪到该辅助索引页已无可用空间时;
- Master Thread
查看Merge Insert Buffer
用户可用通过SHOW ENGINE INNODB STATUS来查看插入缓冲的信息:
seg size代表 Insert Buffer大小,size代表已经合并记录页的数量,inserts代表了插入记录数,merged recs代表了合并的插入记录数量,merges代表合并的次数,也就是实现读取页的次数。
以上是关于InnoDB Insert Buffer相关的内容。