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

数据页与索引页的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. python 深拷贝及浅拷贝区别

    深拷贝及浅拷贝区别 浅拷贝copy: 可变类型:(列表,字典,集合)copy函数对可变类型的第一层对象进行拷贝,对拷贝的对象开辟新的内存空间进行存储,不会拷贝对象内部的子对象 不可变类型:(数字,字符 ...

  2. sqlsever中使用的 select top n在mysql 语句中如何更改

    string sqlSelect = "select top(3) ROW_NUMBER() over(order by UserTime) as Num,* from " + & ...

  3. C++ 函数与数组

    C++ 函数与数组 #include<iostream> using namespace std; const int ArSize = 8; int sum_arr(int arr[], ...

  4. OO课程第三阶段(实验和pta试题)总结Blog3

    OO课程第三阶段(实验和pta试题)总结Blog3 前言:学习OOP课程的第三阶段已经结束了,在此进行对于知识点,题量,难度的个人看法. 学习OOP课程的第三阶段已经结束了,较第一次阶段学习难度加大, ...

  5. 修改mysql root密码,在workbench中导入.sql文件

    修改mysql root密码: 1.如果没有配置环境变量,在 \Program Files\MySQL\MySQL Server 8.0\bin 文件下 Shit+右键打开 Powershell 窗口 ...

  6. PLC入门笔记4

    逻辑指令及其应用 基本逻辑指令 续电器 PLC 公式 扩展逻辑指令 1.置位和复位线圈 置位ON/复位OFF (SET/RST) 不推荐置位复位线圈  可以用更好的方式去表达.. 2.能流取反开关 取 ...

  7. 黑马 java.lang.IllegalArgumentException: Property ‘dataSource‘ is required

    现象: 按照教程步骤做的,但连单元测试都无法通过,会出现java.lang.IllegalArgumentException: Property 'dataSource' is required这个错 ...

  8. 3-1 熟悉Hadoop及其操作

    Hadoop最早起源于Nutch.Nutch的设计目标是构建一个大型的全网搜索引擎,包括网页抓取.索引.查询等功能,但随着抓取网页数量的增加,遇到了严重的可扩展性问题--如何解决数十亿网页的存储和索引 ...

  9. egret tween 屏幕震动动画 ts

    let orig = { x: this.x, y: this.y }; var dir = 1; var tox = 0; var toy = 0; var count = 40; // if (n ...

  10. HTML笔记(二) HTML标签元素

    一 常用的头部元素标签 <head>元素包含了所有的头部标签元素. 1.<title> <title>标签定义了HTML文档的标题,在HTML/XHTML文档中是必 ...