• Buffer Cache


    Buffer Cache

        Buffer Cache是SGA区中专门用于存放从数据文件中读取的的数据块拷贝的区域。Oracle进程如果发现需要访问的数据块已经在buffer cache中,就直接读写内存中的相应区域,而无需读取数据文件,从而大大提高性能(内存的读取效率是磁盘读取效率的14000倍)。Buffer cache对于所有oracle进程都是共享的,即能被所有oracle进程访问。

    一、CBCHash BucketHash Chain List

        CBC链,用来查找block是否在buffer cache中的时候,需要用到,用以快速定位BufferOraclebuffer cache中所有的buffer通过一个内部的Hash算法运算之后,将这些buffer放到不同的 Hash Bucket中。每一个Hash Bucket中都有一个

    Hash Chain List,通过这个list,将这个Bucket中的block串联起来,Hash Chain List是一个双向链表。

     

        从图中我们可以看到,一个latch:cache buffers chains(CBC可以保护多个Hash Bucket,也就是说,如果我要访问某个block,我首先要获得这个latch,一个Hash Bucket对应一个Hash Chain List,而这个Hash Chain List挂载了一个或者多个Buffer Header

     

    二、racle对数据块的访问过程

    1、对该Block运用Hash算法,得到Hash值。

    2、获得cache buffers chains latch

    3、到相应的Hash Bucket中搜寻相应Buffer Header

    4、如果找到相应的Buffer Header,然后判断该Buffer的状态,看是否需要构造CR Block,或者Buffer处于pin的状态,最后读取。

    5、如果找不到,就从磁盘读入到Buffer Cache中。(物理读)

    latch:cache buffers chains的等待事件

    Oracle9i以前,如果其它用户进程已经获得了这个latch,那么新的进程就必须等待,直到该用户进程搜索完毕(搜索完毕之后就会释放该latch)。从Oracle9i开始 cache buffers chains latch可以只读共享,也就是说用户进程A以只读(select)的方式访问Block,这个时候获得了该latch,同时用户进程B也以只读的方式访问Block,那么这个时候由于是只读的访问,用户进程B也可以获得该latch。但是,如果用户进程B要以独占的方式访问Block,那么用户进程B就会等待用户进程A释放该latch,这个时候Oracle就会对用户进程B标记一个latch:cache buffers chains的等待事件。

    latch:cache buffers chains解决:

    1、优化SQL大量逻辑读的SQL语句就有可能产生非常严重的latch:cache buffers chains等待,因为每次要访问一个block,就需要获得该latch,由于有大量的逻辑读,那么就增加了latch:cache buffers chains争用的机率。

    2、Hash Bucket太少,需要更改_db_block_hash_buckets隐含参数9i之后就基本不会出现这个问题了。

    三、LRU List

    1、LRU的引入

    数据从DBF文件中加载到buffer cache的过程中,首先会使用FreeBuffer 来缓存DBFBlock。当数据库使用一段时间后,Buffer Cache中将不存在FreeBuffer,这个时候,应该使用什么样的Buffer来缓存数据块呢?

    我们介绍下Buffer的几种状态。当buffer没有被使用的时候,状态是Free的,一旦缓存数据,状态立马变成clean的。如果这个buffer的数据被更改了,但是没有被提交,这个时候,状态就是dirty的。一旦提交,就会重新变成clean的。回到上面的问题,FreeBuffer使用完了,最合理的,应该是使用什么样的buffer呢?Oracle给我们的答案是:使用“最近使用最少的”clean块,做为替换对象!Oracle数据库的buffer cache是很大的,如果一个个去比较,寻找,效率是极低的。所以,oracle引入LRU的概念。

    LRU是一个双向链表,LRU链表的两端就分别叫做最近使用端(the Most Recently Used MRU)和最近最少使用端(LRU)。如果一个用户进程发现某个block不在Buffer Cache中,那么用户进程就会从磁盘上将这个block读入Buffer Cache。在将block读入到Buffer Cache之前,首先要在LRU list上寻找Freebuffer,如果没有找到,就找最近最少使用端(LRUbuffer,用以缓存数据。

    2、LRU算法及改进

        普通LRU算法的实现原理是每访问一个buffer,就把这个buffer移到MRU端。由于在oracle内部,访问buffer的频率非常高,不断的移动bufferLRU中的位置开销相当大,并且不利于并发。所以oracleLRU进行了改进。

    (1) REPL链表

         oracle对传统的LRU算法进行了改进。在每个buffer header增加了一个计数器(称为touch count,简称为TCH)和一个时间戳。每次访问buffer后,如果上次更新buffer headerTCH是在3秒之前,则对TCH1,并把buffer header中的时间戳更新为当前时间。 

         oracleREPL链表增加了一个字段cold_hd,可以理解为cold_hd后面的大部分buffer都是冷块。我们现在读取一个没有被缓存的data block,需要从REPL链表上得到一个buffer来缓存当前的data block。首先从LRU端获取一个buffer,如果是一个冷快(通过TCH来判断),则使用这个buffer缓存当前的data block,并把这个buffer header移到cold_hd的位置,更新TCH1;如果是一个热快(通过TCH来判断),把这个buffer header移到MRU端,并更新TCH为原来的一半,然后继续检查LRU端的buffer是否是一个冷块,直到找到一个冷块为止。

    (2) REPLAX链表

        REPL中淘汰一个buffer需要很多操作,比如判断是否被锁住,是否是dirty块。相对来说,REPL淘汰一个buffer是一个重量级操作。为此,oracle 增加了另外一个链表REPLAX(replacement list auxilitary),这个链表里的所有buffer可以立即被淘汰,不用检查是否是dirty buffer、是否被pinned。从REPLAX链表淘汰buffer是轻量级操作。 

        oracle启动时,所有buffer header都挂在REPLAX上,随着计数器的增加,这些buffer header会被从REPLAX移到REPL中。当DBWndirty块写入到磁盘后,这些buffer会移到到REPLAX

    3、全表扫描

    对大表全表扫描时,如果上述改进LRU算法的淘汰策略,会导致所有热快被立即换出。oracle首先会对表大小进行评估,进行大表进行全表扫描时,对大表的buffer采用不同的淘汰策略。

    (1)表大小> cache10%。第一次扫描当作大表来对待,计数器不增加,并且buffer header放入REPLAX链表。如果表数据还在缓存的情况下又进行的全部扫描,则认为这个把这个表当作小表扫描来对待,增加计数器。

    (2)表大小> cache25%。计数器的值不会增加,且表对应的buffer header只会出现在REPLAX链表上。

        create table时,使用cache子句也会影响buffer的淘汰侧路。cache子句包括3个选项CACHENOCACHECACHEREADSCACHE适用于经常被访问的小表,NOCACHE适用于大表和访问频次低的表,CACHE READS适用于包含LOB的表。

    四、LRU Write List

      用户提交commit, buffer并没有写入dbf文件,而只是记入了redo log中。真正将脏buffer写入到dbf文件中的是DBWRITER。而DBWRITER是怎么个什么样的后台进程呢?

    1、DBWRITER进程

    Oracle最繁忙的两个后台进程之一,负责将脏buffer写入dbf中。

    2、DBWRITER触发条件

    后台进程DBwriter,在以下几种条件下触发:

    1)每隔一个时间段触发(例如3秒)。

    2PGA没有找到干净的块,触发。

    3)当达到扫描块数限制后还没有找到空闲buffer,就需要通知DBW0将脏缓存回写到磁盘

    3LRU Writer List

    有了DBWRITER,那么它需要怎么选择buffer cache中的buffer写入dbf中呢?Oracle引入了LRUW链表。LRUW将脏块按照被访问的频率链起来,方便DBWRITER从冷端开始写入脏buffer

    五、Buffer的状态分析

     x$bh  每一个buffer在这个表中都有一行数据。

    Buffer Cache中的Buffer有多种状态(x$bh:

    0, FREE, no valid block image

    1, XCUR,单实例的数据库,直接对应数据库的块。增删改查都需要对该buffer进行操作。

    2, SCUR,  RAC多实例的数据库才会存在。

    3, CR, XCUR还没有提交时,其他会话进行读操作时,oracle构造出来的buffer。读完,就没有存在的意义了。

    4, READ, oracle正在加载block时,为read状态。

    7,WRITE  DBWriter正在写

  • 相关阅读:
    Java中printf
    error C3688: invalid literal suffix '__FSTREXP'; literal operator or literal operator template 'operator ""__FSTREXP' not found
    C# IIS 访问网络映射磁盘 读取文件列表
    datatables 参数详解
    Telnet协议详解
    WCF中的ServiceHost初始化两种方式
    C# FTP 上传、下载、获取文件列表
    Oracle存储过程编译卡死的解决方法
    oracle 查询表结构
    Oracle大数据常见优化查询
  • 原文地址:https://www.cnblogs.com/ironyoda/p/6050141.html
Copyright © 2020-2023  润新知