Mysql 百问系列:Buffer Pool 是什么?

Mysql 百问系列:Buffer Pool 是什么?

问题背景知识若是没有Buffer Pool ,那么查询流程会如何?Buffer Pool 如何提升写的效率的脏页存在的价值?页的替换规则因此要淘汰哪些页面呢?结语mysql

问题

  1. 为何会须要 Buffer Pool ?
  2. Buffer Pool 为何能提升读写效率?
  3. 什么是缓存命中?

背景知识

在讲解Buffer Pool 以前须要知道一些背景知识:web

  1. InnoDB 类型的存储引擎是会把数据写到磁盘上的。(Mysql 5.6.6 之后默认) InnoDB 以表为单位,生成 表名.frm 和 表名.idb 文件 存储在相应的Mysql存储目录下。
  2. InnoDB 是以 页(通常为大小为16K) 为单位,从磁盘文件中读取数据 到内存的。 一页 包含多条记录(每页至少要有2条记录)。 记录有更新也是以页为单位刷新到磁盘中。每一页中的记录都是按照索引 大小顺序排序。

若是没有Buffer Pool ,那么查询流程会如何?

让咱们来模拟一个简单的场景,假设有个表school , 其中有1000条数据,如今执行查询redis

select  * from school where id = 400
复制代码

咱们须要获取 id 为400的学校全部信息。算法

  1. 那么InnoDB 须要先找到 id =400 这条记录所在的页,把这页读取到内存,而后从这页的全部记录中找到id=400那条记录返回。
  2. 输出结果到客户端,释放内存。

查询完id =400 后,又来了一条查询语句:sql

select  * from school where id = 401
复制代码

因而Innodb 又得按照上面流程再走一遍, 从磁盘中找到对应的页面,放到内存, 找到结果释放内存。
那么分析上面的过程,咱们能够知道每次搜索都会进行磁盘IO,而磁盘IO的速度相对于CPU,内存的计算速度是远远不及的。
为了避免每一次搜索都须要进行磁盘IO, 那么InnoDB 引入了 Buffer Pool 来充当缓存``
因此查询流程就变为:数据库

  • 先在Buffer Pool中查找 id= 400 这条记录所在的页,若是该页存在,则直接查询到记录返回,若是该页不存在,则从磁盘进行读取,放入Buffer Pool,返回记录。

(这个过程就是咱们平时使用redis充当缓存的过程。先判断某个key 存不存在,若是存在则读取记录返回,若是不存在,则查询数据库,将记录存放到redis ,返回记录。)缓存

Buffer Pool 的功能就是 缓存“页” ,减小磁盘IO,提升读写效率。app

Buffer Pool 如何提升写的效率的

如今咱们须要给某个学习修更名称,假设原来 id=400 的学校名称为 “aa"学习

update school set name = 'xs' where id = 400
复制代码

更新语句的流程为:spa

  1. 查找 数据页 是否在Buffer Pool 中,若是存在,直接更新内存。不存在则从磁盘读取数据到Buffer Pool 中,而后更新。 (这过程其实还涉及到表是否存在非惟一索引,以及change buffer。 )
  2. 将更新内容写入redo log (什么是redo log ? 它是作什么用的?挖个坑之后填。)

从上面流程中发现一个问题没有, 咱们知道Buffer Pool 是一块内存空间,咱们修改了Buffer Pool 中的记录,可是并无把记录从新写回到磁盘文件中。也就是说此时磁盘中记录的信息 和 Buffer Pool 中记录的信息是不一致的。
例子中 这个时候 磁盘中id=400 对应的记录学校名称仍是"aa" ,而 Buffer Pool 中对应名称则为“xs"。

这种磁盘记录的信息与Buffer Pool 记录的信息不一致的页, 称为脏页



脏页存在的价值?

这种磁盘和Buffer Pool 记录信息不一致的状况还会有价值? 咱们来想一下这种状况,好比咱们须要批量更新一批数据。

update school set name = 'xs' where id > 400
复制代码

这个时候会找到Buffer Pool中对应的页,而后修改。 例子中600条记录有大几率是存在在同一页面中的。上面提到过页中的记录是按索引排序的,并且通常16K大小的页,能存放的记录数是几百上千条。
因为不是每一条记录更改都会更新到磁盘,因此上面的更新语句大大节省了时间,毕竟写数据到磁盘是十分耗时的。

固然脏页也不可能一直存在在Buffer Pool 中,总要将信息刷新到磁盘中。否则若是程序出问题,或者机器断电,更新的信息不就丢失了嘛。
那么何时会把Buffer Pool 中的信息更新到磁盘中呢?

  • Mysql 会有专门的后台线程,每隔一段时间就将脏页 刷新到磁盘
  • Buffer Pool 空间不足, 脏页将被淘汰 从 Buffer Pool 中移除的时候
  • redo log 写满的时候
  • 数据库正常关闭的时候。

页的替换规则

Buffer Pool 是一片内存空间,受制于内存空间大小。 能够经过innodb_buffer_pool_size 来控制Buffer Pool 的大小。因此Buffer Pool 内存放的页 数量也是有限的。假设Buffer Pool 中只能存放1000个页,而且已经存满。 那么若是下一次查询的记录并不在这1000页中,须要从磁盘读取相应页 加载到Buffer Pool 中。因为Buffer Pool 已经满了,因此必需要把其中某一个页面先移除, 才能把新的页面放进来。

因此要淘汰哪些页面呢?

咱们知道若是查询或者修改记录,记录的页已经存在在Buffer Pool 中那么将有效的提升效率。最理想的状况是每次访问页面都已经存在在Buffer Pool 中,咱们称为 缓存命中。淘汰页面的算法,对 缓存命中率 相当重要。
因为Buffer Pool的缓存淘汰规则比较复杂,后面另开一篇进行讲解。核心思想就是把最近最少使用的页面淘汰,也就是 LRU (Least recently used)算法。

结语

  • Buffer Pool 是一块内存空间。 将页面加载到Buffer Pool 中能够减小磁盘IO 提升查询效率。
  • 每次更新先更新Buffer Pool 中的记录,并将存放该记录的页标记为 脏页。后台进程每隔一段时间刷新脏页到磁盘提升磁盘IO效率。Buffer Pool的引入提高了读写效率。
  • 缓存命中率 体现了Buffer Pool的利用效率。Buffer Pool 经过LRU算法来淘汰页面提升缓存命中率。

喜欢和支持,请关注下我的公众号,谢谢。

相关文章
相关标签/搜索