Mysql InnoDB Buffer Pool( 二 )


  1. 线性预读
    如果顺序访问某个区的页面超过innodb_read_ahead_threshold的值,那么会触发一次线性预读,异步的读取下一个区中全部的页面到buffer pool中 。
  2. 随机预读
    如果某个区的13个连续的也都被加载到buffer pool中,无论是否是顺序读取的页面,都会异步读取本区中所有的其他页面到buffer pool中,innodb_random_read_ahead 设置为on可以开启随机预读
预读的目的是提高语句的执行效率,相当于innodb 认为你会用到,异步的帮你加载到缓存中,后续不需要继续读磁盘 。但是在LRU的管理中,如果预读的页面很多没用用到的话,还将预读的页面放在链表头部,后续淘汰的页面反而是需要用到的,会极大的降低缓存命中率 。预读导致加载到buffer pool中页的不一定会使用到
  • 全表扫描语句
    当一个sql没有合适的索引或者没用where限定条件的时候,innodb会扫描该表聚集索引所有的页 。如果页非常多,buffer pool无法容纳的时候,就会把其他有用的缓冲页进行淘汰,降低缓存命中率 。全表扫描导致许多使用频率低的页被同时加载到buffer pool中,导致使用频率高的页从buffer pool中被移除(这里可以看出LFU算法的好处,哈哈哈)
  • 3.innodb 如何解决预读和全表扫描导致缓存命中率降低的问题innodb 根据一定比例将LRU链表分为两部分:
    • 热数据区:使用频率很高的缓冲页构成,称为young区
    • 冷数据区:使用频率不是很高的缓存页构成,称为old区

    Mysql InnoDB Buffer Pool

    文章插图
    innodb_old_bolocks_pet可以设置old区占用的比列,默认是37%
    3.1解决预读页面后续也许使用不到的问题innodb规定当磁盘某个页面在初次加载到buffer pool中某个缓冲页时,该缓冲页对应的控制块会放在old区域的头部,这样预读到的且后续如果不进行后续访问的页面会逐渐从old区移除,而不影响young区使用频率高的缓冲页 。
    3.2解决全表扫描短时间访问大量使用频率低页面的问题在进行全表扫描时,虽然首次访问放在old区头部,但是后续会马上被访问到,这时候会把该页放在young区域的头部,这样依旧会影响到使用频率高的页面 。
    为了解决这个问题,innodb规定对于某个处于old区的缓冲页第一次访问时,就在其控制块中记录下访问时间,如果后续访问的时间和第一次访问的时间,在某个时间访问间隔内(innodb_old_blocks_time可以进行设置)那么页面不会从old区移动到young区,反之移动到young区中 。这个时间间隔默认时1000ms,基本上多次访问同一个页面中的多个记录的时间不会超过1s 。
    3.3 优化每次都需要移动young区节点到LRU链表头部的问题如果每次访问一个缓冲页都需要移动到LRU链表的头部,像young区中这种热点数据,每次都需要更新链表头部,并且这还是一个高并发操作,需要CAS或者锁,开销也不小 。为了解决这个问题 innodb规定只有被访问的缓冲页位于young区的前1/4范围外,才会进行移动,所以前1/4的高热度的数据,不会频繁移动
    六丶脏页刷盘innodb后台有专门的线程负责将脏页刷新到磁盘