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。
可以在命令行通过如下命令查看对应的页大小:
你可能会有疑问,缓冲池这么洋气的东西,为什么不把所有的数据都放到缓冲池里呢?这样速度岂不是美滋滋,放到磁盘里慢的跟老牛拉车一样。
哎,哥,醒醒,抛开内存的易失性不谈,缓冲池也是有大小限制的。那你可能又有疑惑了,既然缓冲池有大小限制,那我每次都读入的数据页怎么来管理呢。别的数据页都占了地儿了,哪有我的位置?