参考书籍《mysql是怎样运行的》
系列文章目录和关于我
一丶为什么需要Buffer Pool对于InnoDB存储引擎的表来说,无论是用于存储用户数据的索引,还是各种系统数据,都是以页的形式存放再表空间中,归根结底还是存储再磁盘上 。因此InnoDB存储引擎处理客户端的请求是,如果需要访问某个页的数据,需要把完整的页数据加载到内存中,即便是只需要一条数据,也需要把整个页的数据加载到内存后进行读写访问 。如果没用缓存那么一条sql需要进行多次的磁盘IO操作,如果在读写页后将其缓存在内存中,便可以减少这种磁盘IO提高mysql性能 。
二丶InnoDB Buffer Pool及其内部组成InnoDB 会在mysql服务器起到是就向操作系统申请一块连续的内存,(innodb_buffer_pool_size
可以控制大小,单位字节)用来对InnoDB的页做缓存操作 。
Buffer Pool对应一片连续的内存被划分为若干个页面,页面的大小和InnoDB页面大小一致(16kb)每一个buffer pool 页都对应一些控制信息(表空间编号,页号等)这些控制信息被抽象为控制块(后文我们把buffer pool的页称为缓冲页,和表空间中页做区分)
文章插图
三丶空闲缓冲页管理——free 链表从磁盘上读取一个页到buffer pool中时,应该把这个页缓存到哪儿昵 。buffer pool的做法时将空闲的缓冲页对应的控制块作为一个节点放在链表中,这个链表称作free链表 。
文章插图
其中有一个
基节点
负责记录链表的头和尾,每一个空闲的页都将在free 链表中串联起来 , 每当innodb需要缓存一个页的时候,就通过基节点获取一个空闲的buffer pool 缓冲页,然后在这个缓冲页中记录下表空间,页号之类的信息 。然后把缓冲页对应的free链表节点移除 。在缓存一个页的时候,还需要判断当前页是否已经被缓存,innodb 对已经缓存的页,根据其表空间和页号两个值作为hash的key , 建立hash表,这样可以很快的进行判断 。
四丶缓冲页刷盘——flush链表当innodb修改一个磁盘上的页并缓存到buffer pool中 , 这时候内存中缓存的数据和磁盘就不一致这种页称为
脏页
。如果每次执行完修改都立马将数据刷新到磁盘中的页会影响到程序的性能,所以innodb不会立马刷新到磁盘 , 而是使用flush链表
将脏页对应的控制块串联起来文章插图
五丶缓冲空间不够怎么办——LRU链表管理1.简单的LRU链表buffer pool的大小毕竟是有限的 , 当free 链表中不存在更多空闲的缓冲页了,这时候就需要采取一些淘汰策略对一些无用的缓冲页进行淘汰 。
这里就是涉及到两个问题:什么样的缓冲页是无用的,如何维护这些缓冲页来实现此淘汰策略 。这时候自然是使用LRU算法(最近最少使用)淘汰最近最少使用到缓冲页 。LRU算法使用一个链表来实现,当innodb访问某个页的时候:
- 如果该页不在buffer pool中 , 那么把该页从磁盘加载到buffer pool中的缓冲页是,就把该页的控制块放在LRU链表的头部
- 如果该页已经在buffer pool中 , 那么移动节点到LRU链表头部
2.简单LRU链表无法解决的问题
- 预读
innodb认为在执行当前请求的时候,后续可能会读取某些页面的时候,会把这些页面也加载到buffer pool
- 线性预读
如果顺序访问某个区的页面超过innodb_read_ahead_threshold
的值,那么会触发一次线性预读,异步的读取下一个区中全部的页面到buffer pool中 。
- 随机预读
【Mysql InnoDB Buffer Pool】如果某个区的13个连续的也都被加载到buffer pool中,无论是否是顺序读取的页面,都会异步读取本区中所有的其他页面到buffer pool中,innodb_random_read_ahead
设置为on可以开启随机预读
推荐阅读
- 「MySQL高级篇」MySQL锁机制 && 事务
- 【MySQL】Navicat15 安装
- 「MySQL高级篇」explain分析SQL,索引失效&&常见优化场景
- 「MySQL高级篇」MySQL索引原理,设计原则
- MySQL 索引失效-模糊查询,最左匹配原则,OR条件等。
- MySQL 全局锁、表级锁、行级锁,你搞清楚了吗?
- llinux下mysql建库、新建用户、用户授权、修改用户密码
- RedHat7.6安装mysql8步骤
- 究极无敌细节版 Mysql索引
- Mysql通过Canal同步Elasticsearch
- 线性预读