MySQL当你CRUD时BufferPool中发生了什么?

一、前言下面让我们就一起看下,当你执行CURD时,InnoDB的Buffer Pool中都发生了什么!以及Buffer Pool的优化!
二、介绍你知道的,MySQL对数据的增删改查都是内存中完成的,这块内存就是Buffer Pool 。
你可以像下面这样查看下你的MySQL的Buffer的Buffer Pool的默认大小
 

MySQL当你CRUD时BufferPool中发生了什么?

文章插图
 
上图中的0.125单位为GB,转换成MB就是 1024* 1/8 = 128MB
 
 
总结来说,就是MySQL启动后就会为我们初始化好这块Buffer Pool 。如下图:
 

MySQL当你CRUD时BufferPool中发生了什么?

文章插图
 
你可以看着上图,然后读下面这段话:
 
 
MySQL以数据页为单位,从磁盘中读取数据 。数据页被读取到内存中,所谓的内存其实就是Buffer Pool 。
 
 
Buffer Pool中维护的数据结构是缓存页,而且每个缓存页都有它对应的描述信息 。
 
 
由于MySQL刚启动,还没有从磁盘中读取任何数据页到内存(Buffer Pool)中,那此时Buffer Pool中所有的缓存页其实都是空的 。
 
 
除了缓存页之外,你还能看到Buffer Pool中存在三个双向链表 。分别是FreeList、LRUList以及FlushList 。这三个双向链表中维护着缓存页的描述信息 。
 
 
二、好,假设你读取出来了1个数据页 
 
当你通过select读取出一个数据页之后,是需要将这个数据页加载进Buffer Pool中的缓存页中的 。
 
 
那问题来了,MySQL怎么知道该将你读取出来的数据页存放在哪个缓存页中呢?相信你看了上图应该也能想到答案了 。FreeList这个双向链表不是存放了空闲的缓存页的描述信息吗?那从FreeList中取出一个空间缓存页的描述信息不就好了?于是得到了下面这张图:
 

MySQL当你CRUD时BufferPool中发生了什么?

文章插图
 
啰唆一点:对这张图稍微做一下解读:
 
 
InnoDB会将你读取出来的数据页加载进Buffer Pool中的缓存页中,然后缓存页的描述信息也会被维护进LRU链表中 。链表做了冷热数据分离优化,5/8的区域是热数据区域,3/8的区域算是冷数据区域 。(本质上它们都是双向链表),而你新读取的数据页会被放在冷数据区的靠前的位置上 。
 
 
如果你将该数据页读取出来加载进缓存页中后,间隔没到1s,就使用该缓存页 。那么InnoDB是不会将这个描述信息移动到5/8的热数据区域的 。
 
 
但是当超过1s后,你又去读这个数据页 。那这个数据页的描述信息就会被放到热数据区域 。如下图:
 

MySQL当你CRUD时BufferPool中发生了什么?

文章插图
 
三、假设你一次性读取出来了好多数据页 
 
白日梦在第 6 篇文章中跟大家分享过,MySQL是存在预读机制的,感兴趣可关注公众号阅读 。
 
 
假设触发了MySQL的预读机制 。一次性从磁盘中读取来N多个缓存页 。会得到下面这张图:
 

MySQL当你CRUD时BufferPool中发生了什么?

文章插图
 
因为发生了预读,所以你的一次磁盘IO读出了大量的数据页,但是这些数据页中很可能是有一些是你根本不需要的,仅仅是预读把它们级联查出来了 。这时按老规矩,从FreeList中找到空闲的缓存页信息,然后将其从FreeList中移除 。根据找到的空闲缓存页的描述信息,将从磁盘中读取出来的数据页加载进去 。相应的该缓存页的描述信息也会被维护进LRU链表的冷数据区域 。
 
 
这时你就会发现这种冷热数据分离的机制多么妙!即使发生了预读又怎么样?根本没有机会将热数据区的描述信息1挤下去 。当内存不够用了需要将部分缓存页刷新到磁盘中时,那就从冷数据区域开始刷新好了,反正他们本来就不经常被使用 。
 
 
同样的,当你超过1s后又访问了冷数据区的缓存页,比如访问了缓存页66和数据页67,该缓存页对应的描述信息是会被提升到热数据区,于是有了下面这张图:
 

MySQL当你CRUD时BufferPool中发生了什么?

文章插图
 
那,如果你访问上图中的数据页67,它会移动到描述信息66所在节点的前面去吗?


推荐阅读