innodb的LRU链表是有新旧两个队列,所以和LRU算法的Two queues有些类似
当数据要缓存如LRU链表时,先把数据移动到历史访问队列的链表里
如果数据停留时间超过1S,那么就从历史访问队列里移动到热区域的LRU链表里,如果数据停留时间小于1S,那么就不会移动
移动时间是由innodb_old_blocks_time参数控制,innodb_old_blocks_pct参数负责控制旧链表的长度
默认地:old链表占37% new链表占63%
数据淘汰顺序:从热数据区域的头部开始依次淘汰使用次数较少的数据,最后淘汰到old区域的头部,最后淘汰至队尾,之后清理出整个LRU链表。
innodb为了防止缓存污染:
也就是说,在我们扫描数据量比较大的一个表时,有可能将整个表的数据都缓存到LRU链表里,淘汰掉其他有用的数据,为了防止这种情况,innodb引入了一个机制:先将数据移动到旧LRU链表中,然后如果超过了1S,那么就会移动到热数据LRU里。
在移动数据时,会把数据移动到旧LRU链表的头部,当出现全表扫描时,InnoDB先将数据块载入到旧LRU链表上,程序读取数据块,因为这时,数据块在旧LRU链表中的停留时间还不到innodb_old_blocks_time(1S),所以不会被转移到热LRU链表中。这就避免了Buffer Pool被污染的情况。
在innodb_old_blocks_time时间内的全表扫描,都不会污染到热区域的链表。
在LRU初始化时,LRU链表里为空,当读取page数量小于512时,都会标记为young,如果超过了count 512,那么会标记为old。
show engine innodb status\G中buffer pool状态可以看到新旧链表的数据量大小:
可以看到:Old database pages代表old链表中的数据页数量
Pages made young 9, not young 0 9页超过了1S进入热数据区域的,0页没坚持过1S被移除去的
not young过大可能是有很多的全表扫描
单位都是以页为计算,一页在mysql为16K大小