详细:
页,内存中,buffer pool , 默认128M,每一个页默认的是16k,算下来就是有8192块。
Buffer Pool是数据库中我们第一个必须要搞清楚的核心组件,因为增删改操作首先就是针对这个内存中的Buffer Pool里的数据执行的,同时配合了后续的redo log、刷磁盘等机制和操作。
所以Buffer Pool就是数据库的一个内存组件,里面缓存了磁盘上的真实数据,然后我们的系统对数据库执行的增删改操作,其实主要就是对这个内存数据结构中的缓存数据执行的。
不管查询还是修改,会先将页,从磁盘中复制到bufferPool, 在内存中修改后,数据还是要回到磁盘的,这是内存空间可能又腾出来了。
这时,BufferPool的空间可能比较凌乱,有的被占,有的没有被占,当有新的页要放到bufferpool时,这时,就不知道将这新的页放哪里了?
-------------------------------------------------------------------------------------------------------------------------------------------
free链表,用来管理bufferPool的空白页,
其中基节点存:
1,哪个是第一个控制块
2,哪个是最后一个控制块
3,一共有有多少个控制块
控制块很小,存的是BufferPool对应页的指针,
当从磁盘取出一个页放BufferPool时, 先从free链表中找第一个控制块(头),把页数据放到控制块对应BufferPool指针的空间区域,同时把这个控制块从链表中(头)删除。
当BufferPool有页空间空出来时,就将这个页对应指针添加到fee链表中(尾), 在free链表中这样处理性能是很高的。 这样,就很方便的通过链表对BufferPool中的空白页进行管理。
修改数据:将要个修改的数据复制到BufferPool的页,此时修改的页我们叫它脏页,
哪什么时将修改后的数据持久化磁盘呢?
mysql后台是有个进程,定时监控BufferPool哪些页是脏页(从flush链表中查找),然后把脏页持久化到磁盘中
这里又会有一个问题,哪些是脏页,怎么去判断呢
只要在BufferPool更新了页,就将这页地址添加到flush链表中,如果没有这个flush链表,就得在BufferPool中遍历了。
当BufferPool满了解怎么处理?
LRU(Least recently used),最近用的最少的淘汰掉!
同样的,也有一个链表,叫LRU链表,将最近的访问的,就放在第一个, 假如满了,就将LRU链表最后的淘汰。
缓冲池污染。
怎么解决热数据不容易被覆盖呢?
LRU链表(升级版)其实分了热冷区域, 热占5/8,冷占3/8。
来了一个新的查询,会将bufferPool页地址加到LRU链表冷数据区的头节点,再来一个,还是会加到冷数据区的头节点,这里就会有一个问题,一直在操作冷数据区,热数据区没有数据,
那么什么时候,将冷数据的控制块移到热数据区呢?
如果冷数据再次访问,加入冷数据区时间T1,第二次访问时间T2(全表扫描),T2-T1<1s,说明访问间隔很短,被认为是全表扫描,这时冷数据块不会移到热数据区, 如果T2-T1>1S(第一次这个页数据,第二次访问这个页超过1s,innodb才会理解为用户正常访问,如果小于1s,就会被当作全表扫描),就会将这个加到热数据第一个,成为热数据。
另一种解释:
怎么这类扫描大量数据导致的缓冲池污染问题呢?
MySQL缓冲池加入了一个“老生代停留时间窗口”的机制:
(1)假设T=老生代停留时间窗口;
(2)插入老生代头部的页,即使立刻被访问,并不会立刻放入新生代头部;
(3)只有满足“被访问”并且“在老生代停留时间”大于T,才会被放入新生代头部;
LRU
冷数据区域会占满? 占满就会清掉嘛。
上述原理,对应InnoDB里哪些参数?
有三个比较重要的参数。
参数:innodb_buffer_pool_size
介绍:配置缓冲池的大小,在内存允许的情况下,DBA往往会建议调大这个参数,越多数据和索引放到内存里,数据库的性能会越好。
参数:innodb_old_blocks_pct
介绍:老生代占整个LRU链长度的比例,默认是37,即整个LRU中新生代与老生代长度比例是63:37。
画外音:如果把这个参数设为100,就退化为普通LRU了。
参数:innodb_old_blocks_time
介绍:老生代停留时间窗口,单位是毫秒,默认是1000,即同时满足“被访问”与“在老生代停留时间超过1秒”两个条件,才会被插入到新生代头部。