详解MySQL InnoDB存储引擎的内存管理


Posted in MySQL onApril 08, 2021

存储引擎之内存管理

在InnoDB存储引擎中,数据库中的缓冲池是通过LRU(Latest Recent Used,最近最少使用)算法来进行管理的,即最频繁使用的页在LRU列表的最前段,而最少使用的页在LRU列表的尾端,当缓冲池不能存放新读取到的页时,首先释放LRU列表尾端的页。

详解MySQL InnoDB存储引擎的内存管理

上面的图中,我使用8个数据页来表示队列,具体作用,先卖个关子。在InnoDB存储引擎中,缓冲池中页的默认大小是16KB,LRU列表中有一个midpoint的位置,新读取到的数据页并不是直接放入到LRU列表的首部,而是放入到LRU列表的midpoint位置,这个操作称之为midpoint insertion stategy,也叫中间点插入策略。在默认配置下,该位置在LRU长度的5/8处,这也就是上面使用8个数据页的作用。下面的图示意了新的数据页的插入过程:

详解MySQL InnoDB存储引擎的内存管理

mitpoint的位置可通过参数innodb_old_blocks_pct控制,如下:

mysql> show variables like 'innodb_old_blocks_pct';
+-----------------------+-------+
| Variable_name         | Value |
+-----------------------+-------+
| innodb_old_blocks_pct | 37    |
+-----------------------+-------+
 row in set (. sec)

从上面的例子看出,结果是37,这个37意味着新读取的页将被插入到大概距离LRU列表尾端37%的位置,差不多3/8的位置,在InnoDB存储引擎中,midpoint之前的页称为new列表,后面的页称之为old列表,new列表中的页是最为活跃的数据。

为什么不直接把数据页放在LRU队列的首部?

之所以不把新读取的数据页放在LRU队列的首部,是因为某些全表扫描的SQL操作可能会将所有的热点数据都刷新出LRU队列,导致下一次访问热点数据的时候,必须从磁盘中取相应的数据,从而影响缓冲池的效率。为了解决这个问题,InnoDB使用另外一个参数来管理LRU列表,就是innodb_old_blocks_time,用于表示页读取到midpoint之后,多久才会加入到LRU列表的热端。因此当需要执行上述所说的SQL操作时,可以通过下面的方法尽可能使LRU列表中的热点数据不被刷出。

mysql> set global innodb_old_blocks_time=;
Query OK,  rows affected (0.00 sec)

这表示在1000s之后,才允许这些数据刷新到LRU列表的热端。

如果在实际情况中,数据页活跃的比率不止63%,用户还可以通过设置innodb_old_blocks_pct来减少热点页可能被刷出的概率。

mysql> set global innodb_old_blocks_pct=;                                                                                                     
Query OK,  rows affected (0.00 sec)

当数据库刚启动时,LRU的内容是空的,这个时候,所有的数据页都放在Free列表中,当需要从缓冲池中分页时,首先从Free列表中查找是否有可用的Free页,如果存在,则将该页从Free页中删除,然后放入到LRU的列表中。淘汰掉LRU列表末尾的数据页,将该内存空间分配给新的页。这个过程的流程图如下:

详解MySQL InnoDB存储引擎的内存管理

当LRU列表中的页从old部分加入到new部分时,称此时发生的操作是page made young,而因为innodb_old_blocks_time的设置而没有从old部分移动到new部分的操作称之为page_not_made young。可以通过show engine innodb status来观察LRU列表以及Free列表的使用情况和运行状态。

mysql> show engine innodb status\G
***
***
----------------------
BUFFER POOL AND MEMORY
----------------------
Total large memory allocated 
Dictionary memory allocated 
Buffer pool size   
Free buffers       
Database pages     
Old database pages 
Modified db pages  
Pending reads      
Pending writes: LRU , flush list , single page 
Pages made young , not young 
0.00 youngs/s, 0.00 non-youngs/s
Pages read , created , written 
0.00 reads/s, 0.00 creates/s, 0.00 writes/s
No buffer pool page gets since the last printout
Pages read ahead 0.00/s, evicted without access 0.00/s, Random read ahead 0.00/s
LRU len: , unzip_LRU len: 
I/O sum[]:cur[], unzip sum[]:cur[]
--------------
ROW OPERATIONS
--------------
 queries inside InnoDB,  queries in queue
 read views open inside InnoDB
Process ID=, Main thread ID=, state: sleeping
Number of rows inserted , updated , deleted , read 
0.00 inserts/s, 0.00 updates/s, 0.00 deletes/s, 0.00 reads/s
----------------------------
END OF INNODB MONITOR OUTPUT
============================

 row in set (0.00 sec)

    从上面的结果可以看到:当前buffer pool size总共有8191个页,每个数据页的大小是16k,总共的大小是8191*16k=128M的缓冲池,其中Free buffers表示当前Free列表中页的数量。page made young显示了LRU列表中页移动到前端的次数,因为该服务器在运行阶段没有改变innodb_old_blocks_time的值,因此not young为0,youngs/s、non_youngs/s表示每秒这两类操作的次数。

    InnoDB存储引擎从1.0.x版本开始支持压缩页的功能,即将原本16kb的数据页压缩成1KB、2KB、4KB和8KB。对于非16KB的页,是通过unzip_LRU来管理的,上述命令中的第22行就显示了压缩页和非压缩页的信息。

需要注意的一点是Free buffers的值与Database Pages的值之和不一定等于buffer pool size,因为缓冲池中的页可能还会被分配各自适应哈希索引、锁信息等页,而这部分页并不需要LRU算法进行维护。

脏页

     在LRU列表中的页被修改之后,这个页就称之为“脏页”,即缓冲池中的数据页和磁盘上的数据产生了不一致,缓冲池的数据比较新,这时数据库会通过checkpoint机制将脏页刷新回磁盘,而Flush列表中的页也就是脏页列表,脏页既存在于LRU列表中,也存在与Flush列表中,LRU列表用来管理缓冲池中页的可用性,Flush列表用来管理将页刷新回磁盘,二者不影响。Flush列表也可以通过show engine innodb status来查看,前面的结果列表中的第13行,modified db pages就是当前的脏页数量,用户可以通过元数据表INNODB_BUFFER_PAGE_LRU表来查看。

以上就是详解MySQL InnoDB存储引擎的内存管理的详细内容,更多关于InnoDB 内存管理的资料请关注三水点靠木其它相关文章!

MySQL 相关文章推荐
仅用一句SQL更新整张表的涨跌幅、涨跌率的解决方案
May 06 MySQL
MySQL中你可能忽略的COLLATION实例详解
May 12 MySQL
MySQL 可扩展设计的基本原则
May 14 MySQL
Mysql基础知识点汇总
May 26 MySQL
Mysql 如何实现多张无关联表查询数据并分页
Jun 05 MySQL
MySQL 如何设计统计数据表
Jun 15 MySQL
MySQL中datetime时间字段的四舍五入操作
Oct 05 MySQL
mysql中varchar类型的日期进行比较、排序等操作的实现
Nov 17 MySQL
关于mysql中时间日期类型和字符串类型的选择
Nov 27 MySQL
Mysql分库分表之后主键处理的几种方法
Feb 15 MySQL
深入理解MySQL中MVCC与BufferPool缓存机制
May 25 MySQL
mysql5.5中文乱码问题解决的有用方法
May 30 MySQL
MySQL Innodb关键特性之插入缓冲(insert buffer)
Apr 08 #MySQL
如何使用Maxwell实时同步mysql数据
MySQL创建索引需要了解的
Apr 08 #MySQL
MySQL 使用SQL语句修改表名的实现
详解Mysql 函数调用优化
Apr 07 #MySQL
MySQL复制问题的三个参数分析
Apr 07 #MySQL
MySQL pt-slave-restart工具的使用简介
Apr 07 #MySQL
You might like
PHP中字符串长度的截取用法示例
2017/01/12 PHP
layui框架实现文件上传及TP3.2.3(thinkPHP)对上传文件进行后台处理操作示例
2018/05/12 PHP
javascript支持firefox,ie7页面布局拖拽效果代码
2007/12/20 Javascript
使用jquery为table动态添加行的实现代码
2011/03/30 Javascript
在chrome浏览器中,防止input[text]和textarea在聚焦时出现黄色边框的解决方法
2011/05/24 Javascript
JavaScript 函数惰性载入的实现及其优点介绍
2013/08/12 Javascript
JavaScript中Math对象方法使用概述
2014/01/02 Javascript
jquery 判断滚动条到达了底部和顶端的方法
2014/04/02 Javascript
js+CSS实现弹出居中背景半透明div层的方法
2015/02/26 Javascript
Vue列表页渲染优化详解
2017/07/24 Javascript
Vue项目全局配置页面缓存之按需读取缓存的实现详解
2018/08/01 Javascript
vue.js 双层嵌套for遍历的方法详解, 类似php foreach()
2018/09/07 Javascript
Vue项目数据动态过滤实践及实现思路
2018/09/11 Javascript
nodejs npm错误Error:UNKNOWN:unknown error,mkdir 'D:\Develop\nodejs\node_global'at Error
2019/03/02 NodeJs
js实现拖拽元素选择和删除
2020/08/25 Javascript
python使用urlparse分析网址中域名的方法
2015/04/15 Python
PyQt5每天必学之拖放事件
2020/08/27 Python
python 匹配url中是否存在IP地址的方法
2018/06/04 Python
Python常用模块之requests模块用法分析
2019/05/15 Python
Python scrapy增量爬取实例及实现过程解析
2019/12/24 Python
Python基础之变量基本用法与进阶详解
2020/01/03 Python
PyCharm中如何直接使用Anaconda已安装的库
2020/05/28 Python
CSS3 please 跨浏览器的CSS3产生器
2010/03/14 HTML / CSS
深入研究HTML5实现图片压缩上传功能
2016/03/25 HTML / CSS
Otel.com:折扣酒店预订
2017/08/24 全球购物
世界领先的豪华床上用品供应商之一:Bedeck Home
2019/03/18 全球购物
法国房车租赁网站:Yescapa
2019/08/26 全球购物
联强国际笔试题面试题
2013/07/10 面试题
绩效工资分配方案
2014/01/18 职场文书
2014年十八届四中全会思想汇报范文
2014/10/17 职场文书
2014年优秀党员材料
2014/12/18 职场文书
商场广播稿范文
2015/08/19 职场文书
带你彻底理解JavaScript中的原型对象
2021/04/14 Javascript
如何用python绘制雷达图
2021/04/24 Python
何时使用Map来代替普通的JS对象
2021/04/29 Javascript
MySQL基础快速入门知识总结(附思维导图)
2021/09/25 MySQL