我们都知道,MySQL 是基于磁盘存储的数据库,那我们每次查询一个页的记录时都得从磁盘加载整个页进内存然后读取呢,那这样既不是很慢。所以 MySQL 实现了一种叫做 Buffer Pool 的玩意,那 Buffer Pool 是啥玩意呢,我们接着往下看 🤩🤩🤩
一、Buffer Pool
其实,Buffer Pool 是 MySQL 服务器向操作系统申请的一片连续的内存区域,我们可以通过 innodb_buffer_pool_size
设置 Buffer Pool 的大小
小贴士:
innodb_buffer_pool_size
的单位是字节
那么 Buffer Pool 内部是怎么组成的呢?我们都知道,Buffer Pool 也是用来存储从磁盘加载的数据页,我们把它叫做缓存页,它的大小和磁盘上的数据页的大小是一样的,都是 16 KB。但是,我们为了方便管理这些缓存页,所以其实每个缓存页都对应有一个控制信息,它包括了该页所属的表空间、页号、缓冲页在 Buffer Pool 中的内存地址以及链表节点信息。我们把这个控制信息叫做控制块,它在 Buffer Pool 的前面, 而缓存页在 Buffer Pool 的后面,我们还是画一个图吧,这样更加形象一点:
细心的同学可能看到了这个碎片,学过 JVM 的同学都知道 JVM 垃圾回收的时候可能会产生内存碎片是吧,其实这个碎片和那个差不多的,也是不够分配给控制块和缓存页的内存碎片空间
小贴士:其实这个控制块大小不在
innodb_buffer_pool_size
里面,控制块占缓冲页大小的 5% 左右,所以我们实际分配内存的时候会比innodb_buffer_pool_size
设置的大小大 5% 左右
上面说了 Buffer Pool 是 MySQL 服务器向操作系统申请的一片连续的内存区域,当我们调整 Buffer Pool 的大小时,都需要重新向操作系统申请一块连续的内存空间,然后将旧的 Buffer Pool 中的内容复制到这一
块新空间,这是极其耗时的。所以 MySQL 决定以一个 chunk 为单位向操作系统申请空间,即一个 Buffer Pool 由若干各 chunk 组成:
图中是多个 Buffer Pool 实例,我们可以通过指定 innodb_buffer_pool_instances
来控制 Buffer Pool 实例的个数。这样做是为了可以解决并发安全问题 🤭🤭🤭
二、free 链表
在我们执行一个查询语句的时候,我们都会先在 Buffer Pool 里面查