Buffer Pool
1.Buffer Pool的大小
Buffer Pool默认情况下是128MB,实际生产环境下可以对Buffer Pool进行调整,MySQL推荐在专用的数据库服务器上可以将缓冲池大小设置为计算机物理内存大小的80%,用innodb_buffer_pool_size来配置
2.数据页
MySQL对数据抽象出来了一个数据页的概念,他是把很多行数据放在了一个数据页里,也就是说我们的磁盘文件中就是会有很多的数据页,每一页数据里放了很多行数据,当我们需要一行数据的时候,数据库就会找到这行数据所在的数据页,从磁盘文件里把这个数据页加载到Buffer Pool,到了Buffer Pool就叫做缓存页,数据页和缓存页是一一对应的,默认每个数据页16kb
3.描述数据
对于每个缓存页都会有一个描述信息,它包含:缓存页所属的表空间,数据页的编号,缓存页在buffer pool中的地址以及一些其他的信息,每个缓存页都对应一个描述信息,在buffer pool中,描述信息数据放在前面,缓存页数据放在后面,描述数据大概相当于缓存页的5%左右
4.初始化Buffer Pool
当数据库启动的时候,会按照设置的buffer pool大小,再稍微加大一些,去申请内存区域,作为buffer pool内存区域,然后数据会划分出一个个描述数据和缓存页,等我们有需要就会把数据页加载到buffer pool缓存页中
5.free链表
当我们从磁盘文件加载数据页到buffer pool中时,要知道哪些缓存页是空闲的,数据页为buffer pool设计一个free链表,它是一个双向链表,只要缓存页是空闲的,那么他对应的描述数据就会加入到free链表中,每个节点都会双向连接自己的前后节点,组成一个双向链表,除此之外free链表还有一个基础节点,它会引用链表的头节点和尾节点,它里面储存了链表中有多少个描述数据的节点
6.将数据页加载到Buffer Pool中
首先从free链表中获取一个描述数据块,可以获取到这个描述数据块对应的缓存页信息,然后把数据页加载到buffer pool的缓存页中,同时把描述信息写入描述数据块,最后把这个描述数据块从free链表中移除
7.如何知道数据页是否被缓存
数据库会有一个哈希表,每次你读取一个数据页到缓存之后,都会存入这个哈希表中,key就是表空间号+数据页,value就是缓存页的地址,当你要使用数据页的时候,通过"表空间号+数据页号"去哈希表查一下,如果没有就读数据页,如果有就说明已经被缓存了
8.flush链表
我们在内存修改数据页之后肯定是要把修改过后的数据页刷到磁盘上的,数据库在这里引用一个flush链表,flush链表和free链表相类似,凡是被修改过的缓存页都会把他的描述数据块加到flush链表中,后续刷到磁盘上
9.LRU(Least Recently Used)链表
当我们从磁盘加载一个数据页到缓存页的时候,就把这个数据页的描述数据块放到LRU链表头部,如果有个缓存页的描述数据块在LRU链表尾部,当你修改这个缓存页之后,他所对应的描述数据块会移到LRU链表头部
10.不经常用的数据被加载到缓存页
(1)预读机制
当你从磁盘上加载一个数据的时候,他可能会连带着把这个数据页相邻的其他数据页也加载到缓存里去,但是相邻的其他数据页可能从来都不会被访问
- innodb_read_ahead_threshold,默认值是56,如果顺序访问了一个区里多个数据页,访问的数据页的数量超过了这个阈值,此时就会触发预读机制,把下一个相邻中的所有数据页都加载到缓存中去
- 如果buffer pool里缓存了一个区里的13个连续的数据页,而且这些数据页都是比较频繁被访问的,此时会直接触发预读机制,把这个区域的其他数据页都加载到缓存里去,这个机制是通过innodb_random_read_ahead来控制的,它默认是OFF的
(2)全表扫描
全表扫描会一下子把这个表的所有数据页装载到各个缓存页里去,其中可能有大量得数据我们是不会用得,但是它还被加载到了缓存页中
11.LRU链表优化
-
冷热分离
真正得LRU链表会被拆分为两部分,一部分是热数据,一部分是冷数据,这个冷热数据得比例是由innodb_old_blocks_pct参数控制的,默认是37,也就输冷数据占37%,当我们第一次加载数据页得时候会被放到冷数据区域得链表头部,默认情况在1s之后,再次访问缓存页会被加载到热数据区域,这个时间是由innodb_old_blocks_time参数配置,默认是1000ms -
避免热数据区域频繁移动
热数据区域得缓存页可能是经常被访问的,所以这么频繁的进行移动对性能不太友好,LRU链表的热数据区域的后3/4部分的缓存页被访问了才会移动到链表头部去
12.执行CRUD数据库的操作
一边当我们不停的执行CRUD的时候,不停的加载数据到缓存页,free链表中的缓存页不停的在减少,flush链表中的缓存页不停的在增加,lru链表中的缓存页不停在移动,另一边后台线程不停的把LRU冷数据区域和flush链表的缓存页刷入磁盘,flush链表和LRU链表缓存页在减少,free链表缓存页在增加,实在没有缓存页就把LRU冷数据区域尾部的缓存页刷入磁盘