登录 |  注册
首页 >  数据库 · 存储 >  MySql实战精选笔记 >  buffer pool详解

buffer pool详解

Change Buffer 是一种用于缓存二级索引页变化的特殊数据结构,物理上是一颗普通的btree,是缓冲池中独立的一个区域,存储在idbata系统表空间中。当需要修改二级索引页不在缓冲池中而在磁盘中时,会将这些索引页变化缓存在Change Buffer 中。用于在对数据变更时,如果数据所在的数据页没有在 buffer pool 中的话,在不影响数据一致性的前提下,InnoDB 引擎会将对数据的操作缓存在 Change Buffer 中。

在MySQL 5.5 之前的版本中,由于只支持缓存insert操作,所以最初叫做 Insert Buffer,在后来的版本中支持了更多的操作类型缓冲,改叫 Change Buffer(写缓存)

当需要更新一条数据的时候,并不是只是将需要更新的那一条记录从磁盘中读出来,而是以页为单位,将整个页读入内存(在InnoDB中,最小存储单元是页,每个数据页的大小是16KB)。也就是说,如果引擎找到这一行数据,它所在的数据页就都在内存里。

将数据页从磁盘读入内存中涉及到随机IO访问,这里也是数据库中成本最高的操作之一,而利用 Change Buffer 可以减少 随机IO 访问操作,从而提升数据库性能。

changebuffer.png

(InnoDB 存储引擎体系结构 内存中 和 磁盘中的结构 示意图 -- 来自MySQL官网)

从图中可以看出,change buffer 是 buffer pool 中的一部分,虽然 Change Buffer 的名字叫做 buffer。但是他是可以进行持久化的,在右边的磁盘中的 System Tablespace (系统表空间 -- idbata1)可以看到持久化 Change Buffer 的空间以及把这个 Change Buffer 页 的改动记录在 redo log 里。

触发 Change Buffer 持久化操作有以下几种情况:

  1. 数据库空闲时,后台有线程定时持久化

  2. 数据库缓冲池不够用时。

  3. 数据正常关闭时

  4. redo log 写满时

changebuffer2.png

(InnoDB Change Buffer 示意图 -- 来自MySQL官网)

从图上可以看到 Change Buffer 的功能,Change Buffer 中的数据最终还是会刷回到数据原始数据页中。把 Change Buffer 应用到原始的数据页,得到新的数据页的过程称之为merge。merge 过程中 只会将 Change Buffer 中与原始数据页有关的数据应用到原始数据页上。

触发 merge 操作有以下几种情况:

  1. 原始数据页加载到buffer pool时(访问数据页会触发merge)

  2. 后台线程定时merge操作

  3. MySQL 数据库正常关闭时

buffer pool参数配置

Change Buffer 是可以通过命令参数进行控制的,MySQL 数据库提供了两个对 change buffer 的参数。

innodb_change_buffer_max_size

changebuffer3.png

innodb_change_buffer_max_size 表示 Change Buffer 最大大小占 Buffer Pool 的百分比,默认为 25%。最大可以设置为 50%。

innodb_change_buffering

innodb_change_buffering 参数用来控制对哪些操作启用 Change Buffer 功能,默认是:all。

innodb_change_buffering 参数有以下几种选择:

all        默认值。开启buffer
none       不开启change buffer
inserts:  只是开启buffer insert操作
deletes:   只是开delete-marking操作
changes:  开启buffer insert操作和delete-marking操作
purges:   对只是在后台执行的物理删除操作开启buffer功能

什么条件下可以使用 change buffer

了解了 change buffer,那change buffer 是什么时候使用呢?是所有的情况下都可以使用吗?(情况指的是 所有索引类型)。先了解一下普通索引 和 唯一索引之间的区别。

查询之间区别

对于普通索引来说,查询满足条件的第一个记录后,需要查找下一个记录,一直到碰到第一个不满足条件的记录。

对于唯一索引来说,由于索引定义了唯一性,查找到第一个满足条件的记录后,就会停止继续检索。

上边的查询区别对于性能而言都是微乎其微的。上面也说了,因为innodb读写数据是按照页进行读取的,也就是说找到了需要的那条记录时,他所在的数据页也在内存里了,只需要判断下一条数据是不是满足条件即可,这些都在内存中操作的,所以性能基本没有。

但是读到这里的时候,我会有一个想法,因为普通索引是需要对比下一个记录是不是满足条件。如果当前记录是当前数据页的最后一条记录,那是不是就必须要获取下一个数据页了?

因为这里看书中说的是,对于整型字段,一个数据页可以近千个key,出现这种的概率很低。我就在想出现的概率很低,也就是会出现。个人理解:如果真的出现这种情况,需要在进行读取下一个数据页的信息,拿出紧接着的下一条记录进行判断是否满足条件,这里会产生额外的操作成本。

更新之间区别

对于唯一索引来讲,所有的更新操作都需要先进行判断这个操作是否违背唯一性约束。比如,要插入一条记录,就要先判断这个记录是不是存在的,如果需要判断,就必然需要将数据从磁盘读到内存中。这时候数据都已经到了内存页,直接更新内存会更快,就不需要在走change buffer 了。因此唯一索引就不能 使用 change buffer。

对于普通索引来讲,需要分为两种情况:

  • 第一种:这个记录要修改的目标页在内存中。找到需要修改的记录,直接在内存进行修改,语句执行结束。

  • 第二种:这个记录要修改的目标页不在内存中。InnoDB则是会把这个 更新记录的操作 记录在 change buffer 中,语句执行结束。

这样通过 change buffer ,减少了随机访问,更新性能会有所提升。

这里我不知道大家会不会想到一个问题,就是我使用的普通索引,然后进行更新数据,但是我更新完成之后,立刻进行读取数据,性能还会好吗?

这里的答案必然是不好的,反而会差了。我们在了解change buffer 的时候,知道change buffer 只是在下次用到该数据页的时候,会在这个时候 进行 merge 操作。如果说这样访问的话,随机IO访问并不会减少,反而增加了 change buffer 的维护代价。

所以在以下几种情况开启 Change Buffer 是会使得 MySQL 有明显提升:

1、数据库大部分都是非唯一索引;

2、业务是写多读少

3、写入数据之后并不会立即进行读取它。


上一篇: 性别字段为什么不适合加索引
下一篇: 高性能MySQL-Join的底层实现原理
推荐文章
  • mysql只支持一种join算法:Nested-LoopJoin(嵌套循环连接),但Nested-LoopJoin有三种变种:SimpleNested-LoopJoin,IndexNested-LoopJoin,BlockNested-LoopJoin(简单-索引-缓冲区)原理:1.SimpleNe
  • redis是一个内存数据库,一旦断电或服务器进程退出,内存数据库中的数据将全部丢失,所以需要redis持久化 redis持久化就是把数据保存在磁盘上,利用永久性存储介质将数据保存,在特定的时间将保存的数据进行恢复的工作机制redis提供两种持久化机制RDB:存储数据结果,关注点在数据AOF:存储操作
  • 通过SQL的执行过程来介绍MySQL的基础结构.     首先有一个user_info表,表里有一个id字段,执行下面这条查询语句:Select * form user_info where i
  • 索引(Index)是帮助MySQL高效获取数据的数据结构,索引的目的在于提高查询效率,就像字典和书籍的目录一样,有了目录,可以帮助你快速查找你需要的内容。可以理解为一个排好序的快速查找数据结构。也就是
  • 说到数据库事务,大家脑子里一定很容易蹦出一堆事务的相关知识,如事务的ACID特性,隔离级别,解决的问题(脏读,不可重复读,幻读)等等,但是可能很少有人真正的清楚事务的这些特性又是怎么实现的,为什么要有四个隔离级别。今天我们就先来聊聊MySQL中事务的隔离性的实现原理,后续还会继续出文章分析其他特性的
  • 前面我们系统了解了一个查询语句的执行流程,并介绍了执行过程中涉及的处理模块。相信你还记得,一条查询语句的执行过程一般是经过连接器、分析器、优化器、执行器等功能模块,最后到达存储引擎。那么,一条更新语句
学习大纲