MySQL缓冲池buffer pool
Posted BBinChina
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL缓冲池buffer pool相关的知识,希望对你有一定的参考价值。
概要
在应用系统分层结构中,我们经常会使用缓存(cache)来加速数据的访问。
同理的,mysql作为一个存储系统,同样采用了缓存方式,而在MySQL中叫做缓冲池(buffer pool)
机制,用来避免每次查询数据时进行磁盘IO。
InnoDB的缓冲池缓存什么数据?
缓存用于缓存数据加速访问,那么InnoDB主要缓存的是表数据与索引数据,既然缓存数据可以加速访问,那为何不缓存所有的数据呢?
1、数据库的出现就是为了解决数据存储问题,那么其存储的数据可想而知的大。比如磁盘可能有2T数据,但可能可使用的内存只有16G。
因此,我们需要缓存的数据一般都叫热数据
那么该如何管理缓冲池?
预读
磁盘读写,并不是按需读取,而是按页读取,一次至少读一页数据 (OS页一般为4k大小),如果未来要读取的数据在页中,那么就省去磁盘IO。
根据程序的局部性原理 ,预加载是非常有效,因此InnoDB的缓冲池也采用缓存页的方式来缓存数据,一般缓冲池的页为16k
(可相当于4个OS页)。
采用什么算法管理缓冲池的页数据?
LRU(Least recently used),memcache,OS都会用LRU来进行页置换管理
LRU机制:
- 页已经在缓冲池里,需要将页放置头部,没有新进页,所以不用淘汰尾部页。
- 页不在缓冲池里,新进页到头部,再淘汰尾部页。
为了减少数据移动,LRU一般采用链表实现 ,像使用java实现LRU时,常用LinkedHashMap的数据结构
在MySQL中,需要针对LRU做一些优化:
1、当预读将页数据放入缓冲池LRU头部时,但MySQL并没有从该预读也读取数据,业界称为预读失效
MySQL的优化方式:
(1)、将LRU分为两部分
- 新生代(new sublist)
- 老生代(old sublist)
(2)、新生代的尾(tail)连接着老生代的头(head)
(3)、预读页加入到缓冲池时先加入到老生代头部,当真正预读成功时,再加到新生代的头部。如果没有被读取,则会比新生代里的数据更早淘汰出缓冲池
2、当某一个SQL语句,要批量扫描大量数据时,可能导致把缓冲池的所有页都替换出去,导致大量热数据被换出,MySQL性能急剧下降,这种情况叫缓冲池污染。
场景:
当发生全表查询或者扫描大量数据时,可能会预读大量的页,所有的数据页都会被加载到新生代的头部,但只会访问一次,真正的热数据被大量换出
。
MySQL的优化方式:
(1)、老生代停留时间窗口
机制:
- 假设T=老生代停留时间窗口;
- 插入老生代头部的页,即使立刻被访问,并不会立刻放入新生代头部;
- 只有满足“被访问”并且“在老生代停留时间”大于T,才会被放入新生代头部;
show variables like '%innodb_buffer_pool_size%';
参数:innodb_buffer_pool_size
介绍:配置缓冲池的大小,在内存允许的情况下,DBA往往会建议调大这个参数,越多数据和索引放到内存里,数据库的性能会越好。
show variables like '%innodb_old_blocks_pct%';
参数:innodb_old_blocks_pct
介绍:老生代占整个LRU链长度的比例,默认是37,即整个LRU中新生代与老生代长度比例是63:37。
show variables like '%innodb_old_blocks_time%';
参数:innodb_old_blocks_time
介绍:老生代停留时间窗口,单位是毫秒,默认是1000,即同时满足“被访问”与“在老生代停留时间超过1秒”两个条件,才会被插入到新生代头部。
总结
(1)缓冲池(buffer pool)是一种常见的降低磁盘访问的机制;
(2)缓冲池通常以页(page)为单位缓存数据;
(3)缓冲池的常见管理算法是LRU;
(4)InnoDB对LRU进行了优化:
- 将缓冲池分为老生代和新生代,缓冲池的新页,优先进入老生代,当页被访问,才进入新生代,以解决预读失效的问题。
- 页被访问时,且在老生代停留时间超过配置阈值的,才进入新生代,以解决批量数据访问,大量热数据淘汰的问题
以上是关于MySQL缓冲池buffer pool的主要内容,如果未能解决你的问题,请参考以下文章