大部分数据库都需要将数据读入到内存中处理,而数据库中的内存和buffet不一样,并不是无限量供应的。所以对待buffer chache 需要有一个清理的过程,保证新的数据能如期的导入到buffer Cache中。
在ORACLE 中将数据导入到BUFFER中和清理都需要提到 LRU 队列,通过LUR 来进行数据的导入BUFFER 和清理。 ORACLE中的LRU 连接着每个BUFFER 块。
Oracle的 LRU 和 辅助LRU 链表,请见上图。每一个BUFFER CACHE 块都有一个 TCH 的计数器,每3秒钟计数一次,3秒钟内如果有访问这个块的进程,则这个块就在TCH 计数器上加一。
物理访问LRU 链表的流程如下
1 服务器中的进程要物理读取X号文件的Y块数据,首先进程会搜索HASH表
2 在没有搜索到的情况下,说明内存中并没有这个数据,首先先读 cache buffers lru chain latch,获得写入的权利,从辅助的LRU的尾端搜索可以进行使用的BUFFER CACHE 块,或者说叫可以覆盖的 BUFFER CHACHE块
3 覆盖的标准是,辅助LRU中的块TCH 值小于2, 并且不是脏块。
4 将这个已经写入数据的 辅助 LRU的块,移动到冷LRU中的头部
5 如果LRU 中的辅助LRU是空的,则从冷LRU中获取可以使用的BUFFER CACHE 块。
6 同样是哪个规定,冷链中的BUFFER CACHE块不能是脏块,同时也不能是TCH 值大于等于2的
7 如果在冷LRU中,一个快被多次读取,则直接将块迁移至热LRU中并将TCH清零。
8 同时热LRU中的不被读取的块将被挤出到冷LRU中
同时ORACLE也会定时 3秒一次的搜索冷LRU中不在被读取的块,将其移动到辅助LRU中。保证辅助LRU总是会有可以被使用的 BUFFER 块。
这里还有一个特殊的情况,如果ORACLE 进行全表扫描,则数据是装入到内存中,还是不。
ORACLE 这里面会对扫描的表进行判断,如果表的大小大于SGA的2%说明是大表,则扫描的过程,数据块是不会进入主LRU中的,是能使用辅助LRU空间,并且大表的扫描很可能会自动选择不再进入到ORACLE的BUFFER CACHE中。
可以通过下面的语句,来查看当前ORACLE中的BUFFER CACHE的辅助LRU占总体的百分比。
LRUW 脏链表
在ORACLE 中脏块也是要刷新到磁盘中的,LRUW则就是将脏块刷新到磁盘的链表,当我们有脏块的情况下,在LRU 链表中,脏块并不是马上要刷新到磁盘中的。而是有一定的方式
1 脏块必须TCH 小于 2 才能刷新到(黑色块是 TCH< 2)
2 热区的脏块并不会被刷新到磁盘中
3 只有冷区的脏块会被刷新到磁盘中
4 每3秒会查找LRU的冷区的脏块是否符合标准
5 符合标准的脏块会放入到LRUW 链表 (脏块被放入 LRUW 列表)
6 在每三秒会将这些LRUW 的脏快移动到辅助LRUW链表
7 在LRUW 辅助链表,会将这些脏快进行合并和减少I/O操作(放入LRUW 辅助列表,刷盘)
8 脏块写入磁盘后,从CKPT-Q 列表清除
9 将处理的块放入 LRU 辅助链表,等待下一次的使用(刷新完的块,放入LRU 辅助列表备用)
同时也有特殊的情况,就是如果LRUW 中的脏块超过buffer总数的 25%,则不再3秒进行刷盘,而是直接就触发刷盘的操作。
暂到这里。