MySQL中的这个池子,强的一批!
Mysql 中数据是要落盘的,这点大家都知道。读写磁盘速度是很慢的,尤其和内存比起来更是没的说。但是,我们平时在执行 SQL 时,无论写操作还是读操作都能很快得到结果,并没有预想中的那么慢。
可能你会说我有索引啊,有索引当然快了。但是铁子,索引文件也是存储在磁盘上的,查找过程会产生磁盘 I/O。如果同时对某行数据进行多次操作,那岂不是要重复产生很多次磁盘 IO 吗?
可能你想到了,那我把数据存在内存里不就可以了吗?内存速度比磁盘快,这准没毛病。没错,那该怎么存呢? 这就是我们今天所要讲的主题——缓冲池(buffer pool)。
各位看官,请跟我来~
图注:思维导图
初识缓冲池
上边我们提到过了,执行 SQL 对某一行进行操作时,总不能每次都直接进行磁盘操作吧。好歹有个缓冲地带,不然每次都深入老巢这谁受得了。
这不缓冲池就应运而生了,简单来说就是一块内存区域。它存在的原因之一是为了避免每次都去访问磁盘,把最常访问的数据放在缓存里,提高数据的访问速度。
了解了它的作用,接下来让我们先来看下缓冲池在整个 Mysql 架构里处于什么样的地方,有一个宏观的认识。
我们再来看看它的内部组成部分。在缓冲池中,除数据页和索引页外还有多种类型:
缓冲池的应用
缓冲池你也了解了,可能此时你最关注的是它在 SQL 执行时起了一个什么样的作用。上篇文章中我们简单的提到过一条 SQL 语句的执行过程,但并未涉及到缓冲池相关的问题。这期我们仍是以一条 SQL 来作为切入点。
当一条 SQL 执行的时候,如果是读操作,要查找的数据所在的数据页在内存中时,则将结果返回。否则会把对应的数据页加载到内存中,然后再返回结果。
同样对于写操作来说。如果要修改的行所在的数据页在内存中,则修改后返回对应的结果(当然还有后续操作)。如果不在的话,则会从磁盘里将该行所对应的数据页读到内存中再进行修改。
好了,现在让我们回到开始时候的问题。为什么操作磁盘慢,但是 SQL 执行却不慢呢。到这里相信你也差不多知道了吧。
缓冲池的存在,很大程度减少了磁盘 I/O 带来的开销。要操作的数据行所在的数据页如果存在于缓存中的话,就不需要从磁盘中进行读取。这样在执行后就可以很快拿到结果。
缓冲池的预读机制
我们可以看出来,只要不存在或减少磁盘 I/O,执行速度自然就会变快。那么对于加载数据页这种无法避免的磁盘 I/O 来说是否有更好的方式呢?既然避免不了,那减少磁盘 I/O 的次数总可以吧?
这就是我们要讲的 Mysql 中「预读」的新特性,它是 Innodb 通过在缓冲池中提前读取多个数据页来优化 I/O 的一种方式。因为磁盘读写的时候,是按照页的方式来读取的(你可以理解为固定大小的数据,例如一页数据为 16K),每次至少读入一页的数据,如果下次读取的数据就在页中,就不用再去磁盘上读取了,从而减少了磁盘 I/O。
可以在命令行通过如下命令查看对应的页大小:
缓冲池的空间管理
你可能会有疑问,缓冲池这么洋气的东西,为什么不把所有的数据都放到缓冲池里呢?这样速度岂不是美滋滋,放到磁盘里慢的跟老牛拉车一样。
哎,哥,醒醒,抛开内存的易失性不谈,缓冲池也是有大小限制的。那你可能又有疑惑了,既然缓冲池有大小限制,那我每次都读入的数据页怎么来管理呢。别的数据页都占了地儿了,哪有我的位置?
这里我们来聊聊缓冲池的空间管理,其实对缓冲池进行管理的关键部分是如何安排进池的数据并且按照一定的策略淘汰池中的数据,保证池中的数据不“溢出”,同时还能保证常用数据留在池子中。
传统 LRU 淘汰法
缓冲池是基于传统的 LRU 方法来进行缓存页管理的,我们先来看下如果使用 LRU 是如何管理的。
LRU,全称是 Least Recently Used,中文名字叫作「最近最少使用」。从名字上就很容易理解了。
这里分两种情况:
(1)缓存页已在缓冲池中
这种情况下会将对应的缓存页放到 LRU 链表的头部,无需从磁盘再进行读取,也无需淘汰其它缓存页。
如下图所示,如果要访问的数据在 6 号页中,则将 6 号页放到链表头部即可,这种情况下没有缓存页被淘汰。
(2)缓存页不在缓冲池中
缓存页不在缓冲中,这时候就需要从磁盘中读入对应的数据页,将其放置在链表头部,同时淘汰掉末尾的缓存页
如下图所示,如果要访问的数据在 60 号页中,60 号页不在缓冲池中,此时加载进来放到链表的头部,同时淘汰掉末尾的 17 号缓存页。
是不是看上去很简单,同时也能满足缓冲池淘汰缓存页的方法?但是我们来思考几个问题:
预读失效
上面我们提到了缓冲池的预读机制可能会预先加载相邻的数据页。假如加载了 20、21 相邻的两个数据页,如果只有页号为 20 的缓存页被访问了,而另一个缓存页却没有被访问。此时两个缓存页都在链表的头部,但是为了加载这两个缓存页却淘汰了末尾的缓存页,而被淘汰的缓存页却是经常被访问的。这种情况就是预读失效,被预先加载进缓冲池的页,并没有被访问到,这种情况是不是很不合理。
缓冲池污染
还有一种情况是当执行一条 SQL 语句时,如果扫描了大量数据或是进行了全表扫描,此时缓冲池中就会加载大量的数据页,从而将缓冲池中已存在的所有页替换出去,这种情况同样是不合理的。这就是缓冲池污染,并且还会导致 MySQL 性能急剧下降。
冷热数据分离
这样看来,传统的 LRU 方法并不能满足缓冲池的空间管理。因此,Msyql 基于 LRU 设计了冷热数据分离的处理方案。
也就是将 LRU 链表分为两部分,一部分为热数据区域,一部分为冷数据区域。
当数据页第一次被加载到缓冲池中的时候,先将其放到冷数据区域的链表头部,1s(由 innodb_old_blocks_time 参数控制) 后该缓存页被访问了再将其移至热数据区域的链表头部。
可能你会有疑惑了,为什么要等 1s 后才将其移至热数据区域呢?你想想,如果数据页刚被加载到冷数据区就被访问了,之后再也不访问它了呢?这不就造成热数据区的浪费了吗?要是 1s 后不访问了,说明之后可能也不会去频繁访问它,也就没有移至热缓冲区的必要了。当缓存页不够的时候,从冷数据区淘汰它们就行了。
另一种情况,当我的数据页已经在热缓冲区了,是不是缓存页只要被访问了就将其插到链表头部呢?不用我说你肯定也觉得不合理。热数据区域里的缓存页是会被经常访问的,如果每访问一个缓存页就插入一次链表头,那整个热缓冲区里就异常骚动了,你想想那个画面。
那咋整呢?Mysql 中优化为热数据区的后 3/4 部分被访问后才将其移动到链表头部去,对于前 1/4 部分的缓存页被访问了不会进行移动。
好了,到这里关于 buffer pool 的知识就讲完了。这期里我们讲了 buffer pool 能使 SQL 执行变快的原因,同时还讲了有关 buffer pool 空间的管理方式。欢迎在留言区里进行讨论。
总结
缓冲池的应用
缓冲池很大程度减少了磁盘 I/O 带来的开销,通过将操作的数据行所在的数据页加载到缓冲池可以提高 SQL 的执行速度。
缓冲池的预读机制
为了减少磁盘 I/O,Innodb 通过在缓冲池中提前读取多个数据页来进行优化,这种方式叫作预读。
缓冲池的空间管理
传统的LRU方法对于缓冲池来说,会导致预读失效和缓冲池污染两种情况,因此这种传统的方式并不适用缓冲池的空间管理。
基于对 LRU 方法的优化,Msyql 设计了冷热数据分离的处理方案,将LRU链表分为热数据区和冷数据区两部分,这样就可以解决预读失效和缓冲池污染的情况。
关于作者
作者:大家好,我是莱乌,BAT搬砖工一枚。从小公司进入大厂,一路走来收获良多,想将这些经验分享给有需要的人,因此创建了公众号【IT界农民工】。定时更新,希望能帮助到你。同时,我给大家肝了一份Redis面经手册,在我的公众号内回复【pdf】即可获取,希望对你有所帮助。
MySQL中的这个池子,强的一批!的更多相关文章
- 【转】MySQL中varchar最大长度是多少?
一. varchar存储规则: 4.0版本以下,varchar(20),指的是20字节,如果存放UTF8汉字时,只能存6个(每个汉字3字节) 5.0版本以上,varchar(20),指的是20字符,无 ...
- MySQL(五) MySQL中的索引详讲
序言 之前写到MySQL对表的增删改查(查询最为重要)后,就感觉MySQL就差不多学完了,没有想继续学下去的心态了,原因可能是由于别人的影响,觉得对于MySQL来说,知道了一些复杂的查询,就够了,但是 ...
- 【转】Mysql中varchar存放中文与英文所占字节异同
本文转自Ruby china, 原文地址:https://ruby-china.org/topics/24920 一.关于UTF-8 UTF-8 Unicode Transformation Form ...
- MYSQL中关于日期处理的函数
< DOCTYPE HTML PUBLIC -WCDTD HTML TransitionalEN> MySQL数据库中SQL语句中 关于日期.时间\时间戳的函数 一 MySQL 获得当 ...
- 详细解读MySQL中的权限
一.前言 很多文章中会说,数据库的权限按最小权限为原则,这句话本身没有错,但是却是一句空话.因为最小权限,这个东西太抽象,很多时候你并弄不清楚具体他需要哪 些权限. 现在很多mysql用着root账户 ...
- int(11)最大长度是多少,MySQL中varchar最大长度是多少(转)
int(11)最大长度是多少,MySQL中varchar最大长度是多少? int(11)最大长度是多少? 在SQL语句中int代表你要创建字段的类型,int代表整型,11代表字段的长度. 这个11代表 ...
- mysql中limit与in不能同时使用的解决方式.
mysql中limit与in不能同时使用的解决方式. 分类: MySQL2011-10-31 13:53 1277人阅读 评论(0) 收藏 举报 mysqlsubquery MySQL5.1中子查询是 ...
- mysql中整数类型后面的数字,是不是指定这个字段的长度?比如int(11),11代表11个字节吗?
原文地址: http://www.cnblogs.com/stringzero/p/5707467.html 原先对mysql不太理解,但也没有报错.但理解的不够深入.这次补上. 原来以为int ...
- Mysql中的Prepared Statement与Stored Precedure学习
可以参考: http://stackoverflow.com/questions/196652/prepared-statement-vs-stored-procedure They are not ...
随机推荐
- 笔试题.NET基础代码面试题
题目如下,本随笔只是记录,都是一些自身面经的题目,您既然点开了的话,学习下无妨,说不定有帮助呢 以下答案都经过博主一个个去运行过. 题目1 (实例化后 x=?;y=? 输出什么): public cl ...
- 深入剖析HashMap
前言 很高兴遇见你~ HashMap是一个非常重要的集合,日常使用也非常的频繁,同时也是面试重点.本文并不打算讲解基础的使用api,而是深入HashMap的底层,讲解关于HashMap的重点知识.需要 ...
- 题解-CF1444C Team-Building
题面 CF1444C Team-Building 给 \(n\) 个点 \(m\) 条边,每个点有颜色 \(c_i(1\le c_i\le k)\),求有多少个颜色对两组点并后是二分图. 数据范围:\ ...
- SpringBoot添加多数据源mysql和oracle
项目结构 多数据源配置文件 MultiDataSourceConfig.java SqlSessionTemplate1.java SqlSessionTemplate2.java package c ...
- 10分钟快速入门vue.js
Vue.js是一个轻巧.高性能.可组件化的MVVM库,一套用于构建用户界面的渐进式框架,上手简单,兼容强大. 官方文档:https://cn.vuejs.org/v2/guide/ 下面我们就直接来使 ...
- STL——容器(Map & multimap)的插入与迭代器
1. 容器(Map & multimap)的插入 map.insert(...); //往容器插入元素,返回pair<iterator,bool> map中插入元素的四种方式 ...
- PHP判断字符串所属编码:ASCII、GB2312、GBK、UTF-8、ISO-8859-1
ASCII: ASCII的编码范围为0-127(十六进制:0x00-0x7F),判断函数: function isasciistr($str){ for($i=0;$i<strlen($str) ...
- Python定时任务利器—Apscheduler
导语 在工作场景遇到了这么一个场景,就是需要定期去执行一个缓存接口,用于同步设备配置.首先想到的就是Linux上的crontab,可以定期,或者间隔一段时间去执行任务.但是如果你想要把这个定时任务作为 ...
- Bug java 安全证书
在一个改修项目里,安全性方面总是出一个bug,错误信息如下: xception in thread "main" javax.crypto.BadPaddingException: ...
- wsgi和asgi的关系
什么是WSGI #CGI CGI(Common Gateway Interface,通用网关接口),定义客户端与Web服务器的交流方式的一个程序,例如正常情况下客户端发送过来一个请求,根据HTTP协议 ...