学习了小青蛙老师的文章。总结一下吧。

MySQL的数据都是存放在磁盘中,而磁盘的读写又是非常慢的,因此为了加快数据访问速度,MySQL会把数据放在缓存里,这个缓存就是buffer pool(缓冲池)

#缓冲池是是什么

是MySQL服务器启动时向内存申请的一块连续的空间,可以使用下面的语句查看MySQL申请的空间大小,

我这里是134217728字节,也就是128M。

#如何管理

MySQL会维护一个free链表,记录的是当前buffer pool里空闲的页。每当有新的页进来的时候,先看有没有剩余空间,有的话直接从free链表申请一页放下,同时把这页从free链表删掉。

所以每次MySQL读取一页的时候,会先到缓冲池中查找该页是否在缓冲池中,在的话直接拿。查询是否在的话利用的是哈希,用表空间+页号作为key,对应的页作为value,就可以很快的判断某页是否在缓冲池中了。

#缓存页的替换

MySQL缓存页的替换也是用了大名鼎鼎的LRU算法,即最近最少使用。会把最近使用次数最少的替换出去。

不过MySQL也不是简单的使用LRU。而是做了一些改变。

#为何改变

由于有下面两个问题,所以MySQL对LRU做了一些改变:

预读失效

由于预读,把一些页提前放到了缓冲池,但是最终MySQL并没有从页中读取数据

缓冲池污染 由于某些操作需要扫描全表,这样每次操作都会把缓冲池的数据全部替换一遍,会严重影响其他查询对缓冲池的使用,大大降低缓存命中率。 比如以下语句

因为like不能命中索引,必须全表扫描,会访问到大量的页。

首先把页加到缓冲池中,查到old区域头部;

从页里读数据(会被放到young区域头部)

row里比较,符合条件就加到结果集

直到扫描完所有页中的row. 所有的页都会被加到young区域头部,但是只会访问一次,真正的热数据被大量替换走了。 可以结合这里理解:mp.weixin.qq.com/s/nA6UHBh87…

#如何改变

把LRU链表分成了两部分,一部分是young区域,一部分是old区域。两部分各占的比例可通过下面的语句查询,比如我这里查询到的是old区域占比37%。

针对预读失效问题,某个页首次从磁盘加载到缓冲池的时候,会首先放到old区域的头部,如果之后这些页面没有被读取使用,最终会从old区域尾部剔除。如果被读取(预读成功),才会加到young区域头部。

针对缓冲池污染问题,某个页首次从磁盘加载到缓冲池的时候,会首先放到old区域的头部,即使立刻被访问,并不会马上放到young区域头部,只有满足被访问并且在old区域停留时间大于T的 才会被放入young区域。

这里的T可以通过下面的语句查看,我这里默认设置的是1000ms。