1:一切从数据库的增删改查开始
- Buffer Pool?在数据库中是一个非常重要的组件,我们知道我们的数据最终都是保存在磁盘中的,但是我们每次查询或者修改都不可能从磁盘中去拿数据吧。这样的话我们查询或者修改的性能就会非常低。
- 所以MySql有个Buffer Pool来解决这个问题,Buffer Pool就是MySql数据库中的一块内存,我们实际的操作数据库数据其实都是会在这块内存中操作
2:Buffer Pool长什么样子
- Buffer Pool是MySql中的一块内存,默认是128MB,当然我们也可以自己设置,使用 innodb_buffer_pool_size=2147483648
- 数据页:既然我们知道数据是存放在Buffer Pool中的,那么我们的数据又是如何放在Buffer Pool中的呢??是一行一行的放还是其它方式存放的??-- 实际上MySql抽象出了一个数据页的概念。MySql把很多条数据都放在同一个数据页中。如下图所示
-- 所以当我们要更新一条数据,首先会找到这行数据所在的数据页,然后从磁盘文件里把这行数据所在的数据页直接加载到Buffer Pool中,如下图?
- 缓存页对应的描述细信息:对于每一个缓存页,它实际都有一个描述信息,这个描述信息大体可以认为是用来描述这个缓存页的,比如包含如下这些信息:这个数据页所属的表空间,数据页编号,这个缓存页在Buffer Pool中的地址以及一些别的信息,所以此时我们看下面的图,Buffer Pool实际看起来长这个样子
-- 这里我们要注意一点,Buffer Pool的描述数据大概相当于缓存页的5%左右,假设你设置的Buffer Pool的大小是128Mb,实际上可能会大一些,因为他里面还要存放信息描述数据
3:如果数据库突然挂了,那么内存中的数据怎么办??
- 因为我们在更新数据的时候都是在Buffer Pool中操作,这时候更新之后的数据还在Buffer Pool中,还没有刷到磁盘中去,如果这时候MySql挂了,那么内存中的数据就会没有了,那怎么办呢?? 这就需要MySql的几种日志文件来保证我们的数据不会丢失了
4:从磁盘读取数据页到Buffer Pool的时候,free链表有什么用??
- 现在我们知道当我们要更新一条数据的时候,首先会去磁盘拿到这条数据所在的数据页,然后将整个数据页加载到Buffer Pool中,我们知道数据页与缓存页是一一对应的,也就是从磁盘读取一个数据页之后,会从Buffer Pool中找到一个空闲的缓存页,然后将数据页放进去,那么现在问题来了,MySql是怎么知道哪些缓存页是空闲的呢??
- free链表:是一个双向链表,在我们第一次启动MySql的时候,整个Buffer Pool都是空的,所有的缓存页也都是空闲的,这时候,MySql会将所有的空闲的缓存页的描述数据块都放到free这个链表中去,当我们从磁盘中加载数据页的时候,会从旁free链表中拿到一块空闲的缓存页的描述数据块,然后将这个数据页放到缓存页中,最后将这个缓存页从free链表中删除
5:当我们更新Buffer Pool中的数据的时候,flush链表有什么用??
- 当我们执行增删改操作的时候,如果发现Buffer Pool中没有数据就会从磁盘中加载对应的数据页,然后从free链表中拿到一块空闲的缓存页将数据页放到缓存页中。之后对该数据页中的数据进行操作的时候就直接在Buffer Pool中进行了,这时候你更新了一条数据,那么缓存中的数据与磁盘中的数据就不一致了,这时候就产生了脏页了
- 当产生了脏页之后,MySql需要将这些脏页刷新到磁盘中去。但是我们也不能将所有的缓存页都刷到磁盘中去吧,其实我们只需要把那些被修改过的也就是脏页刷到磁盘就行了,这时候flush链表的作用就体现出来了,只要是被修改过的缓存页,都会被放到一个flush链表中,下次只需要将flush链表中的缓存页刷到磁盘就行了,flush链表整体跟free链表是差不多的
6:如果Buffer Pool满了该怎么办??Lru链表是做什么的??
- 我们知道Buffer Pool是有大小限制的,不可能让你无限存数据,如果Buffer Pool满了之后该怎么办??MySql会把缓存页里被修改过的缓存页刷到磁盘中去,然后这个缓存页就可以清空了,如果被经常访问的缓存页就会被放到Lru链表的头部,所以每次刷盘都是会从Lru链表尾部去刷盘
7:基于冷热数据分离思想设计Lru链表
- Lru链表会被分为二部分,一部分是热数据,一部分是冷数据,这个冷数据的比例是由innodb_old_blocks_pct参数控制的,它默认是37,也就是冷数据占37%
- 数据页第一次被加载到缓存中去的时候,是会被放到冷数据区域的头部,然后在1s之后你继续访问了这个缓存页,那么这个缓存页就会从冷数据区域移到热数据区域的头部
8:Lru链表是如何进行优化的
- 如果在Lru热数据区域头部的几个缓存页经常被访问,那么访问一次就要移动一次,这样会产生一定的消耗,所以MySql设置了如果是热数据区域的后3/4的缓存页被访问了才会将缓存页移动到头部去
9:题外话:MySql预读机制
- MySql在磁盘读取一个数据页的时候,可能会将相邻的数据页都加载到Buffer Pool中去
- MySql什么时候会触发预读机制??有一个参数是innodb_read_ahead_threshold,它的默认值是56,也就是如果顺序访问了一个区里的多个数据页,访问的数据页超过这个阈值,此时就会触发预读机制如果Buffer Pool里缓存了一个区里13个连续的数据页,而且这些数据都是比较频繁被访问到的,此时就会直接触发预读机制
|