buffer pool

10 分钟阅读 896 字 + 661 词
buffer pool就是innodb引擎的一个缓冲池,来提高数据库的读写性能。
可以通过调整innodb_buffer_pool_size参数来设置buffer pool的大小
buffer pool中存储 **数据页,索引页,undo页,**等。。。
img Innodb 为每一个缓存页都创建了一个控制块 ,控制块信息包括【 缓存页的表空间、页号、缓存页地址、链表节点
img 为了能够快速找到空闲的缓存页,可以使用链表结构,将 空闲缓存页的控制块作为链表的节点 ,这个链表称为 Free链表(空闲链表)
img
如何管理脏页?
还有一个 flush链表 ,与free链表类似,链表的节点也是控制块,在于它的元素都是 脏页
提高缓存命中率
img
  • Free Page(空闲页) ,表示此页未被使用, 位于 Free 链表 ;
  • Clean Page(干净页) ,表 示此页已被使用 ,但是页面未发生修改, 位于LRU 链表.
  • Dirty Page(脏页) ,表示此页「已被使用」且「已经被修改」,其 数据和磁盘上的数据已经不一致当脏页上的数据写入磁盘后 ,内存数据和磁盘数据一致,那么该页就变成了干净页。 脏页同时存在于LRU 链表和 Flush 链表。
简单的 LRU 算法并没有被 MySQL 使用,因为简单的 LRU 算法无法避免下面这两个问题
  • 预读失效;
  • Buffer Pool 污染;
预读失效:mysql在加载数据页时,提前把相邻的数据页一并加载进来,目的是为了减少磁盘IO,但是可能这些被提前加载进来的数据页并没有被访问,相当于这个预读白做了,这个就是预读失效。
如何解决呢?
让预读的页停留在buffer pool里的时间要尽可能的短,让真正被访问的页才移动到LRU链表的头部,从而保证真正被读取的热数据留在buffer pool里的时间尽可能长。
mysql是这样做的,改进了LRU算法,将LRU划分了2个区域:old区域和young区域。这个比例一般是yound:old = 63:37
img
划分这两区域后,预读的页只需要加入到old区域的头部,当页被真正访问的时候,才将页插入yound区域的头部。
如果预读的页一直没有被访问到,就会从Old区域移除,这样就不会影响young区域中的热点数据。
buffer pool污染如何解决?
是什么:当 某一个sql语句扫描了大量的数据(索引失效的时候造成全盘扫描也会) ,在buffer pool空间比较有限的情况下, 可能会将buffer pool里的所有页都替换出去 ,导致大量 热数据被淘汰 ,等这些热数据再次被访问的时候,由于缓存未命中,就会产生大量的磁盘IO,性能 会急剧下降。
所以我们需要提高进入young区域的门槛!
mysql是这样做的,进入到young区域的条件增加了 一个停留在old区域的时间判断。
  • 如果后续的访问时间和第一次访问的时间在某个间隔内,那么该缓存也不会移动到young区域的头部;
  • 如果后续的访问时间和第一次访问的时间不在某个间隔内,那么该缓存会移动到young区域的头部;
也就是说,只有同时 满足被访问 以及 在old区域停留时间超过1秒 (参数innodb_old_blocks_time)这两个条件, 才会进入到young区域头部。 此外,防止频繁移动,只有young区域后3/4的节点被访问了才会移动到头部。