MySQL内存(Buffer Pool)
Buffer Pool
MySQL 的数据存在磁盘,但是不能每次读取数据都从磁盘里去,这样磁盘IO太频繁,存在性能问题。
InnoDB设计了一个缓存池(Buffer Pool),缓冲池在内存中。
默认配置Buffer Pool大小为128MB
,可以通过innodb_buffer_pool_size
参数调整。一般调整为可用物理内存的60%~80%。
Buffer Pool缓存什么?
InnoDB会把存储的数据划分为若干页
,以页作为磁盘与内存的交互的基本单位,一个页默认大小为16KB,Buffer Pool中也是由页
构成。
Buffer Pool除了缓存索引页
和 数据页
,还包括undo页,插入缓存页、自适应哈希索引、锁信息等等。
Buffer Pool管理
InnoDB为每个缓存页都创建了一个控制块(类似于文件系统的PCB)
控制块信息包括:缓存页的表空间、页号、缓存页地址、链表节点等等
空闲页(Free 链表)
为了能够快速找到空闲的缓存页,可以使用链表结构,将空闲缓存页的控制块作为链表的节点,这个链表称为:Free 链表
脏页(Flush 链表)
与Free 链表类似
提高缓存命中率
使用简单的LRU算法会导致两个问题:
- 预读失效
- Buffer Pool污染
预读失效
- MySQL有预读机制:
MySQL在加载数据页时,会提前把它相邻的数据页一并加载进来,目的是较少磁盘IO。原理是程序具有空间局部性。 - 预读失效:这些被提前加载进来的数据页,并没有被访问,相当于这个预读是白做了。这就是预读失效。
- 解决:改进LRU算法,将LRU划分为2个区域:old 区 和 young区
预读的数据页放到old区,真正访问的也放到young区。如果预读也一直没被访问,就会从old区域移除。
young被淘汰的页,会挤到old区的头部。
Buffer Pool 污染
当一个SQL语句扫描大量数据时,会把Buffer Pool的所有数据替换出去,导致大量热数据被淘汰了。
等这些热数据再次被访问时,就没有命中,再次进行磁盘IO,导致性能下降。
解决:
young区里是热数据,提高数据进入young的门槛,可以解决这个问题。
MySQL的解决方法:进入young区条件增加一个停留在old区域的时间判断。 具体如下:
- 如果后续访问时间与第一次访问时间在某个时间间隔内,该缓存页就不会从old区进入young区。
- 相反,该缓存页就会移动移动到young区头部。
这个间隔时间有innodb_old_blocks_time
控制,默认为1s。
也就是说,只有同时满足[被访问]与 [在old区域停留时间超过1s] 这两个条件,才会被插入到young区头部
MySQL针对young区其实做了一个优化,为了防止young区域节点频繁移动到头部。young区前1/4被方位不会移动到链表头部,只有后3/4被访问才会。
脏页刷新时机
以下几种情况会触发脏页的刷新:
- 当 redo log 日志满了,会主动触发脏页刷新到磁盘
- Buffer Pool 空间不足时,需要将一部分数据页淘汰掉,如果淘汰的是脏页,那么需要先将脏页同步到磁盘。
- MySQL认为空闲时,后天线程会定期把适量的脏页刷入磁盘
- MySQL正常关闭之前,会把所有脏页刷入到磁盘。
总结
原文地址:https://blog.csdn.net/ansizy/article/details/142378238
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!