51工具盒子

依楼听风雨
笑看云卷云舒,淡观潮起潮落

InnoDB的插入缓冲和自适应哈希索引

# 前言 {#前言}

为了增加数据库的读能力,InnoDB设计了 Buffer Pool 缓冲池,将热点数据留在内存中,极大提高了数据库的读性能。除此之外,InnoDB还有一种叫做 Change Buffer的特性同样至关重要。

# 为什么需要 Change Buffer {#为什么需要-change-buffer}

相比于顺序读写,随机读写在操作系统上的性能是十分弱的。假设有下面一张表:

CREATE TABLE `food` (
  `id` int NOT NULL,
  `name` varchar(255) DEFAULT NULL,
  `parent_id` int DEFAULT NULL,
  PRIMARY KEY (`id`),
  KEY `idx_name` (`name`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;

1
2
3
4
5
6
7

在上面这张表中定义了一个主键索引,又定义了一个二级索引 idx_name。

当往 food 表里插入数据的时候,数据页的存放按照主键 a 进行顺序存放。但是 idx_name 这个二级索引叶子节点的插入就不是顺序的了,而是需要离散地访问该索引页。前面讲到了,相比于顺序读写,随机读写在操作系统上的性能是十分弱的。

为了降低随机读写对性能的影响,InnoDB 引入了 Change Buffer。在 InnoDB1.0.x 版本之前,Change Buffer 只支持对插入数据的缓存,因此很多地方看到的是 Insert Buffer;后面的版本 Change Buffer 可以对 Insert、Delete、Update 都进行缓冲。

简单来讲,Change Buffer 是将写操作缓存到了 Change Buffer 中,在适当的时机和情况下写入磁盘。

# Change Buffer是如何工作的 {#change-buffer是如何工作的}

对于非唯一辅助索引的变更操作,并不是每次数据的变更都直接将数据插入到索引页中,而是通过下面这个流程来进行处理:

  1. 判断要变更的索引页是否在 Buffer Pool 中,如果在的话直接改索引页。
  2. 如果要变更的索引没在 Buffer Pool 中,将变更额外存储到 Change Buffer 对象中。
  3. 当有查询请求时,InnoDB会将变更和实际的数据进行 Merge 操作,保证数据一致性。
  4. 如果没有查询请求,InnoDB会按照特定的频率和情况将数据合并到磁盘中,将原本的多次写入合并为一次写入,极大提高非唯一辅助索引的插入性能。

Change Buffer 的合并操作主要在以下几个场景下触发

  1. 辅助索引被读取到Buffer Pool的时候:当一段查询操作将辅助索引加载到缓冲池的时候,Change Buffer 中对应的变更信息会进行一次合并。
  2. Change Buffer 达到一定占用空间之后:如果已使用的 Change Buffer 达到了一定占用空间,会直接进行一次合并操作。
  3. Master Thread 定期执行合并 Change Buffer 的操作。

# 为什么Change Buffer只适用非唯一索引 {#为什么change-buffer只适用非唯一索引}

从上面的介绍中已经知道了 Change Buffer 只能用于非唯一辅助索引,但这是为什么呢?

主要的原因是如果这个索引是唯一索引,那就必须去做唯一性校验,因此不得不去磁盘中加载数据。如果此时再放到 Change Buffer 中反而多了一道无用的操作。

# Change Buffer 相关参数 {#change-buffer-相关参数}

change buffer 占用内存大小

show variables like 'innodb_change_buffer_max_size'

1

innodb_change_buffer_max_size 表示 change buffer 最大占用内存的大小,默认为25,表示占用缓冲池大小的25%。

查看 Change Buffer 情况

show engine innodb status

1

找到下面的结果:

-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0

1
2
3
4
5
6
7
8

因为这个数据库是我自己搭着玩的所以几乎没有数据,可以看一下里面的内容

表头还是沿用了历史的 INSERT BUFFER ,后面的 ADAPTIVE HASH INDEX 是自适应哈希索引的内容。

seg size:当前 Insert Buffer的大小2*16KB=32KB;

free list len:空闲列表的长度;

size :已经合并记录页的数量;

merges:合并的次数,也就是实际读取页的次数;

merged operations 中:

insert:insert buffer 大小

delete mark:delete buffer 大小

delete:purge buffer 大小

discarded operations 表示已经被丢弃的操作信息。比如缓存了一些对表的变更操作,但是这张表被删除了,就无需再做合并了。

# 自适应哈希索引 {#自适应哈希索引}

在上面查看 Change Buffer 情况的时候,可以看到自适应哈希索引的信息也被放在了一个模块上。

-------------------------------------
INSERT BUFFER AND ADAPTIVE HASH INDEX
-------------------------------------
Ibuf: size 1, free list len 0, seg size 2, 0 merges
merged operations:
 insert 0, delete mark 0, delete 0
discarded operations:
 insert 0, delete mark 0, delete 0
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 0 buffer(s)
Hash table size 34679, node heap has 1 buffer(s)
Hash table size 34679, node heap has 1 buffer(s)
Hash table size 34679, node heap has 2 buffer(s)
Hash table size 34679, node heap has 5 buffer(s)
0.00 hash searches/s, 0.00 non-hash searches/s
---

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

自适应哈希索引是对B+树的一种优化,需要注意的是自适应哈希索引不需要手工去配置,完全由 InnoDB 引擎控制。

一般生产环境的数据量下,B+树的层级往往是在3到4层,意味着需要查询3到4次才能查到叶子节点。但是通过哈希索引只需要一次。

自适应哈希索引属于InnoDB层面的优化,无需开发人员手动介入。

赞(3)
未经允许不得转载:工具盒子 » InnoDB的插入缓冲和自适应哈希索引