赞
踩
目录
4、磁盘上的数据页和Buffer Pool中的缓存页是如何对应起来?
6、数据库启动的时候,是如何初始化Buffer Pool的?
如果在Redis里存放了很多缓存数据,那么此时会不会有类似冷热数据的问题?应该如何优化和解决呢?
因为增删改操作首先就是针对这个内存中的Buffer Pool里的数据执行的,同时配合了后续的redo log、刷磁盘等机制和操作。所以Buffer Pool就是数据库的一个内存组件,里面缓存了磁盘上的真实数据,然后我们的Java系统对数据库执行的增删改操作,其实主要就是对这个内存数据结构中的缓存数据执行的。
[server]innodb_buffer_pool_size = 2147483648
实际上默认情况下,磁盘中存放的数据页的大小是16KB,也就是说,一页数据包含了16KB的内容。而Buffer Pool默认128M,则可以容纳8192个数据页。
当你的数据库运行起来之后,你肯定会不停的执行增删改查的操作,此时就需要不停的从磁盘上读 取一个一个的数据页放入Buffer Pool中的对应的缓存页里去,把数据缓存起来,那么以后就可以对这个数据在内存里执行增删改查了。
借助free链表,从free链表里获取一个描述数据块,然后对应的找到这个描述数据块对应的空闲缓存页,然后把磁盘上的数据页读到该缓存页中,同时把相关描述数据写到描述数据块中,并将该描述数据块从free链表中去除。
因为在内存里更新的脏页的数据,都是要被刷新回磁盘文件的。但是,不可能所有的缓存页都刷回磁盘的,因为有的缓存页可能是因为查询的时候被读取到Buffer Pool里去的,可能根本没修改过!
flush链表,这个flush链表本质也是通过缓存页的描述数据块中的两个指针,让被修改过的缓存页的描述数据块,组成一个双向链表。凡是被修改过的缓存页,都会把他的描述数据块加入到flush链表中去,flush的意思就是这些都是脏页,后续都是要flush刷新到磁盘上去的。
故flush链表就是记录脏数据页的。
LRU:一个新的LRU链表了,这个所谓的LRU就是Least Recently Used,最近最少使用的意思。
LRU工作原理:假设我们从磁盘加载一个数据页到缓存页的时候,就把这个缓存页的描述数据块放到LRU链表头部去,那么只要有数据的缓存页,他都会在LRU里了,而且最近被加载数据的缓存页,都会放到LRU链表的头部。然后假设某个缓存页的描述数据块本来在LRU链表的尾部,后续你只要查询或者修改了这个缓存页的数据,也要把这个缓存页挪动到LRU链表的头部去。
也就是说最近被访问过的缓存页,一定在LRU链表的头部。
当你的缓存页没有一个空闲的时候,你是不是要找出来那个最近最少被访问的缓存页去刷入磁盘?此时你就直接在LRU链表的尾部找到一个缓存页,他一定是最近最少被访问的那个缓存页!
MySQL的预读机制:当你从磁盘上加载一个数据页的时候,他可能会连带着把这个数据页相邻的其他数据页,也加载到缓存里去!举个例子,假设现在有两个空闲缓存页,然后在加载一个数据页的时候,连带着把他的一个相邻的数据页也加载到缓存里去了,正好每个数据页放入一个空闲缓存页! 实际上只有一个缓存页是被访问了,另外一个通过预读机制加载的缓存页,其实并没有人访问,此时这两个缓存页可都在LRU链表的前面。
全表扫描机制:能导致频繁被访问的缓存页被淘汰的场景,那就是全表扫描
SELECT * FROM USERS
真正MySQL在设计LRU链表的时候,采取的实际上是冷热数据分离的思想。
原理:数据页第一次被加载到缓存页之后,这个缓存页是放在LRU链表的冷数据区域的头部的,然后必须是1s过后访问换个缓存页,他才会被移动到热数据区域的链表头部。
innodb_old_blocks_time参数,默认值1000,也就是1000毫秒
我们在设计缓存机制的时候,经常会考虑热数据的缓存预加载。
并不是在缓存页满的时候,才会挑选LRU冷数据区域尾部的几个缓存页刷入磁盘,而是
有一个后台 线程,他会运行一个定时任务,这个定时任务每隔一段时间就会把LRU链表的冷数据区域的尾部的一些缓存页,刷入磁盘里去,清空这几个缓存页,把他们加入回free链表去!
这个后台线程同时也会在MySQL不怎么繁忙的时候,找个时间把flush链表中的缓存页都刷入磁盘中,这样被你修改过的数据,迟早都会刷入磁盘的!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。