由于硬盘和内存的造价差异,一台主机实例的硬盘容量通常会远超于内存容量。对于数据库等应用而言,为了保证更快的查询效率,通常会将使用过的数据放在内存中进行加速读取。

数据页与索引页的LRU

数据页和索引页的目的在于缓存一部分的表数据和索引数据,其数据总量通常会超过缓冲池大小,所以缓冲池中应只缓冲那些经常使用的热点数据。InnoDB内存管理使用的是最近最少使用(Least Recently Used, LRU)算法。来淘汰最久未使用的数据。

在一般的LRU算法中,当链表中的某一个数据被读取时,将会将其放置于队首。当新增数据且链表已达最大数量时,将链表尾部的数据移除,并将新增的数据置于链表首部。

InnoDB的LRU并没有使用传统的双端链表,而是做了改进,这里有两个问题:

  • 预读失效
  • 缓冲池污染

优化预读失效

由于预读(Read-Ahead),提前把页放入了缓冲池,但最终 MySQL 并没有从页中读取数据,称为预读失效。

Read-Ahead机制

Read-Ahead用于异步预取buffer pool中的多个page的一个预测行为。

InnoDB使用两种提前预读Read-Ahead算法来提高I/O性能。

  • Linear read-ahead 线性预读

如果一个extent中的被顺序读取的page超过或者等于   innodb_read_ahead_threshold  参数变量时,Innodb将会异步的将下一个extent读取到buffer pool中,innodb_read_ahead_threshold可以设置为0-64的任何值(注:innodb中每个extent就只有64个page),默认为56。值越大,访问模式检查就越严格。

  • Random read-ahead 随机预读

如果当同一个extent中连续的13个page在buffer pool中发现时,Innodb会将该extent中的剩余page读到buffer pool中。控制参数  innodb_random_read_ahead  默认没有开启。

如何对预读失效进行优化?

要优化预读失效,思路是:

  • 让预读失败的页,停留在缓冲池LRU里的时间尽可能短
  • 让真正被读取的页,才挪到缓冲池LRU的头部

InnoDB 的具体解决方法

由上图可以看出 InnoDB 将 LRU List 分为两部分,默认前 5/8 为 New Sublist(新生代)用于存储经常被使用的热点数据页,后 3/8 为 Old Sublist(老生代),新读入的数据页默认被放到 Old Sublist 中,只有满足一定条件后,才会被移入 New Sublist。

新生代和老生代代比例在 MySQL 中通过参数 innodb_old_blocks_pct 控制,值的范围是5到95.默认值是37(即池的3/8)。

  • 如果数据页真正被读取(预读成功),才会加入到新生代的头部
  • 如果数据页没有被读取,则会比新生代里的“热数据页”更早被淘汰出缓冲池

举个例子,整个缓冲池如图

假如有一个页号为 50 的数据页页被预读加入缓冲池:

(a). 页号为50 的数据页只会从老生代头部插入,老生代尾部(也是整体尾部)的页会被淘汰掉,即 8 号数据页被淘汰。

(b). 假如页号为50 的数据页不被真正读取,即预读失败,它将比新生代的数据更早淘汰出缓冲池

(c). 假如 50 这一页立刻被读取到,例如SQL访问了页内的行row数据。它会被立刻加入到新生代的头部,同时新生代的页会被挤到老生代,此时并不会有页面被真正淘汰

改进版缓冲池LRU能够很好的解决“预读失败”的问题。但仍然无法解决缓冲池被污染但问题。

缓冲池污染

当某一个SQL语句,要批量扫描大量数据时,可能导致把缓冲池的所有页都替换出去,导致大量热数据被换出,MySQL 性能急剧下降,这种情况叫缓冲池污染。

解决方法

缓冲池加入了一个“老生代停留时间窗口”的机制:

(a). 假设T=老生代停留时间窗口

(b). 插入老生代头部的页,即使立刻被访问,并不会立刻放入新生代头部

(c). 只有满足“被访问”并且“在老生代停留时间”大于T,才会被放入新生代头部

假如批量数据扫描,有91、92、93、94、95、96、97、98、99等页面将要依次被访问

如果没有“老生代停留时间窗口”的策略,这些批量被访问的页面,会置换出大量热数据。

加入“老生代停留时间窗口”策略后,短时间内被大量加载的页,并不会立刻插入新生代头部,而是优先淘汰那些,短期内仅仅访问了一次的页。

只有在老生代呆的时间足够久,停留时间大于T,才会被插入新生代头部。

老生代的停留时间由参数 innodb_old_blocks_time 控制,单位为毫秒,默认是1000

总结

  1. 缓冲池(buffer pool)是一种常见的降低磁盘访问的机制
  2. InnoDB的缓冲池以数据页(page)为单位缓存数据
  3. InnoDB 对普通 LRU 进行了优化,
  • 将缓冲池分为老生代和新生代,入缓冲池的页,优先进入老生代,页被访问,才进入新生代,以解决预读失效的问题。
  • 同时采用老生代停留时间窗口机制,当数据页被访问且在老生代停留时间超过配置阈值的,才进入新生代,以解决批量数据访问,大量热数据淘汰的问题
 

InnoDB Buffer Pool改进LRU页面置换的更多相关文章

  1. innodb buffer pool小解

    INNODB维护了一个缓存数据和索引信息到内存的存储区叫做buffer pool,他会将最近访问的数据缓存到缓冲区.通过配置各个buffer pool的参数,我们可以显著提高MySQL的性能. INN ...

  2. 14.4.3.1 The InnoDB Buffer Pool

    14.4.3.1 The InnoDB Buffer Pool 14.4.3.2 Configuring Multiple Buffer Pool Instances 14.4.3.3 Making ...

  3. MySQL · 引擎特性 · InnoDB Buffer Pool

    前言 用户对数据库的最基本要求就是能高效的读取和存储数据,但是读写数据都涉及到与低速的设备交互,为了弥补两者之间的速度差异,所有数据库都有缓存池,用来管理相应的数据页,提高数据库的效率,当然也因为引入 ...

  4. InnoDB存储引擎--Innodb Buffer Pool(缓存池)

    InnoDB存储引擎--Innodb Buffer Pool(缓存池) Innodb Buffer Pool的概念 InnoDB的Buffer Pool主要用于缓存用户表和索引数据的数据页面.它是一块 ...

  5. InnoDB缓存---InnoDB Buffer Pool

    InnoDB Buffer Pool 定义 对于InnoDB存储引擎,不管用户数据还是系统数据都是以页的形式存储在表空间进行管理的,其实都是存储在磁盘上的. 当InnoDB处理客户端请求,需要读取某页 ...

  6. Mysql InnoDB Buffer Pool

    参考书籍<mysql是怎样运行的> 系列文章目录和关于我 一丶为什么需要Buffer Pool 对于InnoDB存储引擎的表来说,无论是用于存储用户数据的索引,还是各种系统数据,都是以页的 ...

  7. [转]MySQL innodb buffer pool

    最近在对公司的 MySQL 服务器做性能优化, 一直对 innodb 的内存使用方式不是很清楚, 乘这机会做点总结. 在配置 MySQL 的时候, 一般都会需要设置 innodb_buffer_poo ...

  8. innodb buffer pool相关特性

    背景 innodb buffer pool作为innodb最重要的缓存,其缓存命中率的高低会直接影响数据库的性能.因此在数据库发生变更,比如重启.主备切换实例迁移等等,innodb buffer po ...

  9. MySQL · 性能优化· InnoDB buffer pool flush策略漫谈

    MySQL · 性能优化· InnoDB buffer pool flush策略漫谈 背景 我们知道InnoDB使用buffer pool来缓存从磁盘读取到内存的数据页.buffer pool通常由数 ...

  10. Innodb buffer pool/redo log_buffer 相关

    InnoDB存储引擎是基于磁盘存储的,并将其中的记录按照页的方式进行管理.在数据库系统中,由于CPU速度和磁盘速度之前的鸿沟,通常使用缓冲池技术来提高数据库的整体性能. 1. Innodb_buffe ...

随机推荐

  1. Mysql存储类型长度

    分析MySQL数据类型的长度 MySQL有几种数据类型可以限制类型的"长度",有CHAR(Length).VARCHAR(Length).TINYINT(Length).SMALL ...

  2. 在CentOS下安装nginx+php环境

    一.nginx 安装 1. 在nginx官网下载nginx源码 提供一个nginx官网下载地址: http://nginx.org/download/nginx-1.12.2.tar.gz 注意:请先 ...

  3. python 购物小程序

    要求:  1.启动程序后,让用户输入预算,然后打印商品列表  2.允许用户根据商品编号购买商品 3.用户选择商品后,检测余额够不够,够就直接付款,不够就提醒 4.可随时退出,推出时打印已购买商品和余额 ...

  4. Linux CentOS Docker Asp.net Core MVC 模板项目的部署

    本文只是记录 .net core 3.1 项目的基本部署方法,灵活应对不同情况与需求 工具:VS 2019    Linux CentOS 7 x64 Xshell     Xftp Docker 安 ...

  5. 【原创】windows环境下Java串口编程

    由于工作中遇到需要读取SBG Ellipse N系列的惯导模块数据,为了方便操作,我选择在Windows下进行串口开发.串口使用RS232. Ellipse-N RS232的引脚定义 开始我尝试使用的 ...

  6. Delphi之不可思议

    1.--------不可思议的函数调用--开始- 开发环境D7 1 function TForm1.GetssA: string; 2 begin 3 Result:=Result+'AA'; 4 e ...

  7. [C#]Event相关的三个典型Case收录.

    基本版: using System; namespace EventDemo1 { public delegate void CatCallEventHandler(); public class C ...

  8. Blob文件下载type类型

    let url = window.URL.createObjectURL(new Blob([文件流(一般为res.data)], {type: "Blob类型"}) let li ...

  9. 在winodws server r2上安装AD域

    一.创建第一个域 服务器管理-管理--添加角色和功能 其他都是默认值,下一步 二.重启后,已域账号登录 三.检查AD域有没有安装成功 1.查看计算机名 更改计算机名 2.检查是否含有以下,AD管理中心 ...

  10. mysql使用support-files下的mysql.server启动报错“Starting MySQL ERROR! Couldn't find MySQL server (/usr/local/mysql/bin/mysqld_safe)”

    报错版本:mysql-5.7.35 1.报错完整提示信息: [root@localhost support-files]# ./mysql.server start ./mysql.server: l ...