什么是数据库的“缓存池”?( 三 )


什么是数据库的“缓存池”?

文章插图
 
8、LRU链表带来的麻烦这里的麻烦指的是就是 MySQL本身的预读机制带来的问题
# 预读机制MySQL 在从磁盘加载数据的的时候,会将数据页的相邻的其他的数据页也加载到缓存中 。# MySQL 为什么要这么做因为根据经验和习惯,一般查询数据的时候往往还会查询该数据相邻前后的一些数据,有人可能会反问:一个数据页上面不是就会存在该条数据相邻的数据吗?这可不一定,某条数据可能很大,也可能这条数据是在数据页在头部,也可能是在数据页的尾部,所以 MySQL 为了提高效率,会将某个数据页的相邻的数据页也加载到缓存池中 。
什么是数据库的“缓存池”?

文章插图
 
上图能够看到B的相邻也被加载到了C描述数据的前面,而实际上C的命中率比B的相邻页高多了,这就是LRU本身带来的问题 。
# 哪些情况会触发预读机制 1. 有一个参数是 innodb_read_ahead_threshold,他的默认值是56,意思就是如果顺序的访问了一个区里的多个数据页,访问的数据页的数量超过了这个阈值,此时就会触发预读机制,把下一个相邻区中的所有数据页都加载到缓存里去(这种就是:线性预读) 2. 如果 Buffer Pool 里缓存了一个区里的13个连续的数据页,而且这些数据页都是比较频繁会被访问的,此时就会直接触发预读机制,把这个区里的其他的数据页都加载到缓存里去(这种就是:随机预读)随机预读是通过:innodb_random_read_ahead 来控制的,默认是OFF即关闭的(MySQL 5.5已经基本飞起该功能,应为他会带来不必要的麻烦,这里也不推荐大家开启,说出来的目的是让大家了解下有这么个东西)还有一种情况是 SELECT * FROM students 这种直接全表扫描的,会直接加载表中的所有的数据到缓存中,这些数据基本是加载的时候查询一次,后面就基本使用不到了,但是加载这么多数据到链表的头部就将其他的经常命中的缓存页直接全挤到后面去了 。
以上种种迹象表明,预读机制带来的问题还是蛮大的,既然这么大,那 MySQL为什么还要进入预读机制呢,说到底还是为了提高效率,**一种新的技术的引进,往往带来新的挑战**,下面我们就一起来看下 MySQL是如何解决预加载所带来的麻烦的 。
9、基于冷热数据分离的LRU链表所谓的冷热分离,就是将 LRU 链表分成两部分,一部分是经常被使用到的热数据,另一部分是被加载进来但是很少使用的冷数据 。通过参数innodb_old_blocks_pct 参数控制的,默认为37,也就是 37%。用图表示大致如下:
什么是数据库的“缓存池”?

文章插图
 
数据在从磁盘被加载到缓存池的时候,首先是会被放在冷数据区的头部,然后在一定时间之后,如果再次访问了这个数据,那么这个数据所在的缓存页对应描述数据就会被放转移到热数据区链表的头部 。
那为什么说是在一定的时间之后呢,假设某条数据刚被加载到缓存池中,然后紧接着又被访问了一次,这个时候假设就将其转移到热数据区链表的头部,但是以后就再也不会被使用了,这样子是不是就还是会存在之前的问题呢?
所以 MySQL通过innodb_old_blocks_time来设置数据被加载到缓存池后的多少时间之后再次被访问,才会将该数据转移到热数据区链表的头部,该参数默认是1000单位为:毫秒,也就是1秒之后,如果该数据又被访问了,那么这个时候才会将该数据从 LRU 链表的冷数据区转移到热数据区 。
现在再回头看下上面的问题
# 通过预加载(加载相邻数据页)进来的数据1. 这个时候就很好理解了,反正数据会被放在LRU链表的冷数据区的(注意:这里说的放在链表中的数据都是指的是<缓存页中的数据所对应的描述数据>),当在指定时候之后,如果某些缓存页被访问了那么就将该缓存页的描述数据放到热数据区链表的头部# 全表扫描加载进来的数据页1. 和上面一样,数据都是先在冷数据区,然后在一定时间之后,再次被访问到的数据页才会转移到热数据区的链表的头结点,所以这也就很好的解决了全表扫描所带来的问题再来思考下 Buffer Pool 内存不够的问题
#Buffer Pool 内存空间不够使用了怎么办?也就是说没有足够使用的空闲的缓存页了 。1. 这个问题在这个时候就显得非常简单了,直接将链表冷数据区的尾节点的描述数据多对应的缓存页刷到磁盘即可 。


推荐阅读