MySQL InnoDB缓存
1. 背景
对于各种用户数据、索引数据等各种数据都是需要持久化存储到磁盘,然后以“页”为单位进行读写。
相对于直接读写缓存,磁盘IO的成本相当高昂。
对于读取的页面数据,并不是使用完就释放掉,而是放到缓冲区,因为下一次操作有可能还需要读区该页面。
对于修改过的页面数据,也不是马上同步到磁盘,也是放到缓冲区,因为下一次有可能还会修改该页面的数据。
但是缓存的空间是有大小限制的,不可能无限扩充。
对于缓冲区的数据,需要有合理的页面淘汰算法,将未来使用概率较小的页面释放或者同步到磁盘,
给当下需要存放到缓存的页面腾出位置。
2. 存储器性能差异
寄存器:CPU暂存指令、数据的小型存储区域,速度快,容量小。
CPU高速缓存(CPU Cache):用于减少CPU访问内存所需平均时间的部件。
内存:用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。
硬盘:分为固态硬盘(SSD)和机械硬盘(HHD),是非易失性存储器。
下图是各种缓存器的价格和性能差距,
从下图可以看出,SSD的随机访问延时在微妙级别,而内存的的随机访问延时在纳秒级别,内存比SSD大概快1000倍左右。
图片来自 小林Coding
3. Buffer Pool
一个缓冲池(缓冲池)是向操作系统申请的一块内存空间,这块内存空间由多个chunk组成,每个chunk均包含多个控制块和对应的缓冲页。
chunk是向操作系统申请内存的最小单位,缓冲页大小与InnoDB表空间使用的页面大小一致。
Buffer Pool的示意图如下

每一个控制块都对应一个缓冲页,控制块包含该缓冲页所属的表空间编号、页号、在Buffer Pool中的地址、链表结点信息等等。
当刚读取一个页面时,需要知道缓冲区有哪些空闲页面,当修改过后缓冲页后,需要记录该缓冲页需要持久化到磁盘,
当缓冲区没有空闲页面了,需要有页面淘汰算法来将缓冲页移出缓冲区,
以上涉及到Free链表、Flush链表、LRU链表,下面注意说明。
4. Free链表
Free链表是由空闲的缓冲页对应的控制块组成的链表,通过Free链表就获取到空闲的缓冲页及其在缓冲区中的地址。
每当需要从磁盘加载一个页面到缓冲区时,从该Free链表取出一个控制块结点,从Free链表移除该结点,并加入LRU链表。
如果这个缓冲区页面被修改过,那么会被加入到Flush链表中。
5. Flush链表
如果一修改缓冲页的数据之后就刷新到磁盘,这种频繁的IO操作势必影响程序等整体性能。
试想一下,先后修改1000次同一缓冲区页面的一字节数据,每次修改都刷新到磁盘,与修改1000次后再将最终结果刷新磁盘,节省了999次刷新磁盘的操作。
因此,当页面的数据被修改之后,需要将改页面放到Flush链表,排队等候写入磁盘。
这既可以减少在用户进程中刷新磁盘的次数,也从整体上减少了磁盘IO到次数。
6. LRU链表
内存空间有限,不可能将所有数据都缓存在内存当中,因此需要有一定的算法将内存中页面淘汰掉(修改过的页面持久化到磁盘)。
LRU(Least Recently Used)链表主要用于辅助实现内存页面淘汰,故名思义,最先淘汰的是最近最少使用的缓冲页。
LRU链表的结果如下图所示

将LRU链表分为young区域和old区域。
对于初次加载到缓冲区的页面,会放到LRU链表old区域的头部,这主要避免了预读的页面被放到了LRU链表的首部。
当第二次访问缓冲页且时间间隔超过innodb_old_blocks_time(默认1s)时,才将该页面移动到LRU链表的首部。
进一步,为了避免频繁的移动链表结点,当某个缓冲页已经在young区域的前3/4时,则不会移动该结点到首部。
7. 其它
如何定位页面是否被缓冲呢?
表空间号和页号可以唯一识别缓冲页,因此InnoDB引擎建立了以表空间号+页号为key,以缓冲页控制块地址为value的哈希表,
从而快速判断页面是否被缓冲,快速定位到数据所在地址。
MySQL InnoDB缓存的更多相关文章
- 浅谈mysql innodb缓存策略
浅谈mysql innodb缓存策略: The InnoDB Buffer Pool Innodb 持有一个存储区域叫做buffer pool是为了在内存中缓存数据和索引,知道innodb buffe ...
- MySQL的Innodb缓存相关优化
MySQL的Innodb缓存相关优化 INNODB 状态的部分解释 通过 命令 SHOW STATUS LIKE 'Innodb_buffer_pool_%' 查看 Innodb缓存使用率 (I ...
- redis作为mysql的缓存服务器(读写分离,通过mysql触发器实现数据同步)
一.redis简介Redis是一个key-value存储系统.和Memcached类似,为了保证效率,数据都是缓存在内存中.区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录 ...
- redis作为mysql的缓存服务器(读写分离) (转)
一.redis简介Redis是一个key-value存储系统.和Memcached类似,为了保证效率,数据都是缓存在内存中.区别的是redis会周期性的把更新的数据写入磁盘或者把修改操作写入追加的记录 ...
- 定点分析: MySQL InnoDB是如何保证系统异常断电情况下的数据可靠性?
MySQL支持事务,所以保证数据可靠的前提是对数据的修改事务已经成功提交 这个问题可以解释为'MySQL InnoDB是如何保证事务C(一致性)D(持久性)性的?' 可能出现的两种情况: (一致性)数 ...
- Mysql 查询缓存总结
Mysql 查询缓存总结 MySQL查询缓存解释 缓存完整的SELECT查询结果,也就是查询缓存.保存查询返回的完整结果.当查询命中该缓存,mysql会立刻返回结果,跳过了解析.优化和执行阶段, 查询 ...
- MySQL InnoDB 存储引擎探秘
在MySQL中InnoDB属于存储引擎层,并以插件的形式集成在数据库中.从MySQL5.5.8开始,InnoDB成为其默认的存储引擎.InnoDB存储引擎支持事务.其设计目标主要是面向OLTP的应用, ...
- mysql innodb存储引擎和一些参数优化
mysql 的innodb存储引擎是事务性引擎,支持acid.innodb支持版本控制和高并发的技术是svcc:需要重点注意:myisam只缓存索引,innodb缓存索引和数据:
- MySQL InnoDB内存压力判断以及存在的疑问
本文出处:http://www.cnblogs.com/wy123/p/7259866.html(保留出处并非什么原创作品权利,本人拙作还远远达不到,仅仅是为了链接到原文,因为后续对可能存在的一些错误 ...
随机推荐
- Linux yum搭建私有仓库
搭建yum仓库需要两种资源: rpm包 rpm包的元数据(repodata) 搭建好仓库后需要使用三种网络协议共享出来 http或https ftp 范例: 使用http协议搭建私有仓库 (本示例使用 ...
- Linux yum的实现和配置
使用yum或dnf解决rpm包的依赖关系. YUM:Yellowdog Update Modifier.是rpm的前端程序 作用:解决软件包之间的依赖关系 yum工作原理: yum 服务器存放rpm包 ...
- python小题目练习(九)
题目:将美元转化为人民币 需求:实现如图所示需求 代码展示: """Author:mllContent:将美元转化为人民币Date:2020-11-23"&q ...
- 到点了开始网抑云(悲)但是用python(整活)
写在前面的一点网抑云: 爱情不是随便许诺好了不想再说了没错 是我那么多的冷漠 让你感觉到无比的寂寞不过 一个女人的不仅仅渴望得到的一个承诺我害怕欺骗也害怕寂寞更害怕我的心会渐渐地凋落爱情不是随便许诺好 ...
- [开源精品] .NET Redis Client 又多了一个选择,还在被 StackExchange.Redis Timeout 问题困扰吗?
前言 .NET 下 RedisClient SDK 选择挺多,国人常用免费的有 StackExchange.Redis/CSRedis/Newlife.Redis,收费的有 ServiceStack. ...
- docker for window WSL 2 installation is incomplete 错误,导致docker无法启动
1.错误截图如下: 2.错误原因:由于wsl2版本旧,根据提示让我们手动更新包,去微软官网下载最新wsl2后,安装完成重启即可解决. 3.下载地址:download地址
- 数码管动态显示Verilog实现(参考小梅哥教程)(视觉暂留)
一个数码管有九个引脚,控制八段二极管的亮灭,用以显示需要的数字. 当有N个数码管时,一个一个控制的话需要N x 9 个引脚,消耗资源较多. 因此可以利用动态显示的方案通过人眼的视觉暂留特性达到静态显示 ...
- mysql8.0二进制安装遇到的问题
公司新项目需要用CentOS8.0以上的系统和mysql8.0:于是在虚拟机上开始操作测试: 一实验环境 1.系统版本:CentOS8.32.数据库版本:mysql-8.0.233.数据库下载链接:h ...
- PLC中增益和偏移
y=kx+b这个直线方程,那么增益就是指k这个斜率,而偏移就是指b. 模拟量转换时一般是不需要设置这两个参数的,只有当外部信号与模块接收的信号在值上有偏差的情况下才会去调整这个参数. 如果的模块信号是 ...
- Java连接数据库从入门到入土
Java连接数据库 一.最原始的连接数据库 是没有导入任何数据源的:只导入了一个数据库驱动:mysql-connector-java-8.0.27.jar 首先是编写db.proterties文件 d ...
