1、高速缓存区结构

oracle为了将物理I/O最小化,把最近使用过的块数据保管在内存的一定区域。这部分内存区域就是高速缓存区。高速缓存区与共享池、重做缓存区成为SGA的最重要的内存区域。利用下面的命令可了解当前实例的高速缓存区大小。

SQL> show sga

Total System Global Area 9620525056 bytes
Fixed Size		    2215704 bytes
Variable Size		 8455717096 bytes
Database Buffers	 1140850688 bytes
Redo Buffers		   21741568 bytes

Database Buffers 相应值就是当前实例的高速缓冲区的大小。oracle为了有效管理高速缓存区,使用Hash Chain结构。Hash Chain位于共享池内,使用oracle典型内存结构的管理方法Bucket->Chain->Header结构。此结构在下面图3上表现。


数据仓库为什么有数据缓冲层 数据库缓冲区高速缓存_cache

Hash Chain结构起点就是Hash表,Hash表由多个Hash bucket组成。一个Hash bucket与Hash函数结果相匹配。oracle对于块地址(DBA,Data Block Address,以File#和Block#组成)和块类应用了简单Hash函数,利用其结果寻找Hash bucket。具有相同Hash值的Buffer Header(buffer header与数据块一一对应,buffer header 里记录的数据块地址和数据块类型。)在Hash bucket上以链(chain)形式相连。Buffer Header拥有对于缓冲区的Meta信息,并拥有缓存区区域实际缓冲区的指针值。请注意:Hash chain位于共享池内,而实际缓存区信息则位于高速缓存区。

Hash Chain结构利用cache buffers chains latch锁存器保护。欲扫描(scan)特定块的进程,必须获得相应块所在Hash Chain管理的cache buffers chains latch锁存器。基本上每次只有一个进程获得仅有的一个cache buffers chains latch锁存器,一个cache buffers chains latch锁存器则管理多个Hash Chain。因此许多进程同时检索高速缓存区时,获得cache buffers chains latch锁存器过程中发生争用,在此过程中等待latch: cache buffers chains事件。oracle 9i开始,将cache buffers chains latch锁存器以Shared模式获得,但只限于只读操作。所以,同时执行只读操作的进程之间能共享cache buffers chains latch锁存器。而对于缓存区获得或释放buffer lock时,需要把cache buffers chains latch锁存器以Exclusive模式获得,所以即便在执行只读操作时,也会发生cache buffers chains latch锁存器争用。

利用以下命令可以得到cache buffers chains latch的数量:

SQL> select count(*) from v$latch_children where name like 'cache buffers chains';  
      
      COUNT(*)  
    ----------  
          4096

还可以查看_db_block_hash_latches隐含参数得到相同的结果:


SQL> select ksppinm, ksppstvl from x$ksppi x, x$ksppcv y
  2    where (x.indx = y.indx) and (translate(ksppinm, '_', '#')) like '_db_block_hash_latches';

KSPPINM 		  KSPPSTVL
------------------------- ----------
_db_block_hash_latches	  4096

而hash bucket数可以利用_db_block_hash_buckets隐含参数查看:


SQL> select ksppinm, ksppstvl from x$ksppi x, x$ksppcv y
  2    where (x.indx = y.indx) and (translate(ksppinm, '_', '#')) like '_db_block_hash_buckets';

KSPPINM 		  KSPPSTVL
------------------------- ----------
_db_block_hash_buckets	  131072

所以,一个cache buffers chains latch管理的hash bucket数就是:131072/4096=32个。



2、Working set

LRU——LRU表示Least Recently Used,也就是指最近最少使用的buffer header链表。LRU链表串连起来的buffer header都指向可用数据块。
LRUW——LRUW则表示Least Recently Used Write,也叫做dirty list,也就是脏数据块链表,LRUW串起来的都是修改过但是还没有写入数据文件的内存数据块所对应的buffer header。
LRU和LRUW总是成对(pair)出现,这一对链被称作working set,即working set=LRU+LRUW。Oracle使用多个working set,而一个cache buffers lru chains latch管理一个working set。要检索LRU或LRUW的进程必须获得cache buffers lru chains latch。因此,许多进行要同时检索LRU或LRUW时,为了获得cache buffers lru chains latch发生锁存器争用,这个过程中等待latch: cache buffers lru chain事件。
可以通过隐含参数_db_block_lru_latches查看cache buffers lru chains latch的数量:

SQL> select ksppinm, ksppstvl from x$ksppi x, x$ksppcv y
  2    where (x.indx = y.indx) and (translate(ksppinm, '_', '#')) like '_db_block_lru_latches'; 

KSPPINM 		  KSPPSTVL
------------------------- ----------
_db_block_lru_latches	  128

但并不是所有缓冲池都能使用以上128个锁存器。oracle有多种缓冲池(buffer pool),各缓冲池分别使用这些锁存器。第一,缓存区大体上分为默认(DEFAULT)缓冲池、KEEP缓冲池、RECYCLE缓冲池;第二,默认缓冲池又可以按块大小分为标准大小、2K、4K、8K、16K、32K缓冲池。每个缓冲池使用独立的cache buffers lru chains latch锁存器,因此锁存器的最小数量是8个。通过接下来的命令,可以确认哪个锁存器正在使用哪个缓存区。


SQL> select d.blk_size, c.child#, p.bp_name, c.gets, c.sleeps
  from x$kcbwds d, v$latch_children c, x$kcbwbpd p
 where d.set_latch = c.addr
   and d.set_id between p.bp_lo_sid and p.bp_hi_sid
 order by c.child#;
  2    3    4    5  
  BLK_SIZE     CHILD# BP_NAME			 GETS	  SLEEPS
---------- ---------- -------------------- ---------- ----------
     16384	    1 KEEP			  784	       0
     16384	    3 KEEP			  784	       0
     16384	    5 KEEP			  784	       0
     16384	    7 KEEP			  784	       0
     16384	    9 KEEP			  784	       0
     16384	   11 KEEP			  784	       0
     16384	   13 KEEP			  784	       0
     16384	   15 KEEP			  784	       0
     16384	   17 KEEP			  784	       0
     16384	   19 KEEP			  784	       0
     16384	   21 KEEP			  784	       0

  BLK_SIZE     CHILD# BP_NAME			 GETS	  SLEEPS
---------- ---------- -------------------- ---------- ----------
     16384	   23 KEEP			  784	       0
     16384	   25 KEEP			  784	       0
     16384	   27 KEEP			  784	       0
     16384	   29 KEEP			  784	       0
     16384	   31 KEEP			  784	       0
     16384	   33 RECYCLE			  784	       0
     16384	   35 RECYCLE			  784	       0
     16384	   37 RECYCLE			  784	       0
     16384	   39 RECYCLE			  784	       0
     16384	   41 RECYCLE			  784	       0
     16384	   43 RECYCLE			  784	       0

  BLK_SIZE     CHILD# BP_NAME			 GETS	  SLEEPS
---------- ---------- -------------------- ---------- ----------
     16384	   45 RECYCLE			  784	       0
     16384	   47 RECYCLE			  784	       0
     16384	   49 RECYCLE			  784	       0
     16384	   51 RECYCLE			  784	       0
     16384	   53 RECYCLE			  784	       0
     16384	   55 RECYCLE			  784	       0
     16384	   57 RECYCLE			  784	       0
     16384	   59 RECYCLE			  784	       0
     16384	   61 RECYCLE			  784	       0
     16384	   63 RECYCLE			  784	       0
     16384	   65 DEFAULT		      1831572	      29

  BLK_SIZE     CHILD# BP_NAME			 GETS	  SLEEPS
---------- ---------- -------------------- ---------- ----------
     16384	   67 DEFAULT		      1834882	      14
     16384	   69 DEFAULT		      1829337	      16
     16384	   71 DEFAULT		      1223036	      15
     16384	   73 DEFAULT		      1249571	      22
     16384	   75 DEFAULT		      1171446	      16
     16384	   77 DEFAULT		      1776088	      17
     16384	   79 DEFAULT		      1778421	       9
     16384	   81 DEFAULT		      1849237	      23
     16384	   83 DEFAULT		      1836658	      12
     16384	   85 DEFAULT		      1813929	      16
     16384	   87 DEFAULT		      1881678	      14

  BLK_SIZE     CHILD# BP_NAME			 GETS	  SLEEPS
---------- ---------- -------------------- ---------- ----------
     16384	   89 DEFAULT		      1845283	      19
     16384	   91 DEFAULT		      1834101	      16
     16384	   93 DEFAULT		      1824715	      15
     16384	   95 DEFAULT		      1834087	      11
      2048	   97 DEFAULT			  784	       0
      2048	   99 DEFAULT			  784	       0
      2048	  101 DEFAULT			  784	       0
      2048	  103 DEFAULT			  784	       0
      2048	  105 DEFAULT			  784	       0
      2048	  107 DEFAULT			  784	       0
      2048	  109 DEFAULT			  784	       0

  BLK_SIZE     CHILD# BP_NAME			 GETS	  SLEEPS
---------- ---------- -------------------- ---------- ----------
      2048	  111 DEFAULT			  784	       0
      2048	  113 DEFAULT			  784	       0
      2048	  115 DEFAULT			  784	       0
      2048	  117 DEFAULT			  784	       0
      2048	  119 DEFAULT			  784	       0
      2048	  121 DEFAULT			  784	       0
      2048	  123 DEFAULT			  784	       0
      2048	  125 DEFAULT			  784	       0
      2048	  127 DEFAULT			  784	       0
      4096	  129 DEFAULT			  784	       0
      4096	  131 DEFAULT			  784	       0

  BLK_SIZE     CHILD# BP_NAME			 GETS	  SLEEPS
---------- ---------- -------------------- ---------- ----------
      4096	  133 DEFAULT			  784	       0
      4096	  135 DEFAULT			  784	       0
      4096	  137 DEFAULT			  784	       0
      4096	  139 DEFAULT			  784	       0
      4096	  141 DEFAULT			  784	       0
      4096	  143 DEFAULT			  784	       0
      4096	  145 DEFAULT			  784	       0
      4096	  147 DEFAULT			  784	       0
      4096	  149 DEFAULT			  784	       0
      4096	  151 DEFAULT			  784	       0
      4096	  153 DEFAULT			  784	       0

  BLK_SIZE     CHILD# BP_NAME			 GETS	  SLEEPS
---------- ---------- -------------------- ---------- ----------
      4096	  155 DEFAULT			  784	       0
      4096	  157 DEFAULT			  784	       0
      4096	  159 DEFAULT			  784	       0
      8192	  161 DEFAULT			  784	       0
      8192	  163 DEFAULT			  784	       0
      8192	  165 DEFAULT			  784	       0
      8192	  167 DEFAULT			  784	       0
      8192	  169 DEFAULT			  784	       0
      8192	  171 DEFAULT			  784	       0
      8192	  173 DEFAULT			  784	       0
      8192	  175 DEFAULT			  784	       0

  BLK_SIZE     CHILD# BP_NAME			 GETS	  SLEEPS
---------- ---------- -------------------- ---------- ----------
      8192	  177 DEFAULT			  784	       0
      8192	  179 DEFAULT			  784	       0
      8192	  181 DEFAULT			  784	       0
      8192	  183 DEFAULT			  784	       0
      8192	  185 DEFAULT			  784	       0
      8192	  187 DEFAULT			  784	       0
      8192	  189 DEFAULT			  784	       0
      8192	  191 DEFAULT			  784	       0
     16384	  193 DEFAULT			  784	       0
     16384	  195 DEFAULT			  784	       0
     16384	  197 DEFAULT			  784	       0

  BLK_SIZE     CHILD# BP_NAME			 GETS	  SLEEPS
---------- ---------- -------------------- ---------- ----------
     16384	  199 DEFAULT			  784	       0
     16384	  201 DEFAULT			  784	       0
     16384	  203 DEFAULT			  784	       0
     16384	  205 DEFAULT			  784	       0
     16384	  207 DEFAULT			  784	       0
     16384	  209 DEFAULT			  784	       0
     16384	  211 DEFAULT			  784	       0
     16384	  213 DEFAULT			  784	       0
     16384	  215 DEFAULT			  784	       0
     16384	  217 DEFAULT			  784	       0
     16384	  219 DEFAULT			  784	       0

  BLK_SIZE     CHILD# BP_NAME			 GETS	  SLEEPS
---------- ---------- -------------------- ---------- ----------
     16384	  221 DEFAULT			  784	       0
     16384	  223 DEFAULT			  784	       0
     32768	  225 DEFAULT			  784	       0
     32768	  227 DEFAULT			  784	       0
     32768	  229 DEFAULT			  784	       0
     32768	  231 DEFAULT			  784	       0
     32768	  233 DEFAULT			  784	       0
     32768	  235 DEFAULT			  784	       0
     32768	  237 DEFAULT			  784	       0
     32768	  239 DEFAULT			  784	       0
     32768	  241 DEFAULT			  784	       0

  BLK_SIZE     CHILD# BP_NAME			 GETS	  SLEEPS
---------- ---------- -------------------- ---------- ----------
     32768	  243 DEFAULT			  784	       0
     32768	  245 DEFAULT			  784	       0
     32768	  247 DEFAULT			  784	       0
     32768	  249 DEFAULT			  784	       0
     32768	  251 DEFAULT			  784	       0
     32768	  253 DEFAULT			  784	       0
     32768	  255 DEFAULT			  784	       0

128 rows selected.

解析以上结果可知:KEEP缓冲池使用16个锁存器,RECYCLE缓冲池使用16个锁存器,对默认缓冲池按块大小各自使用16个锁存器。最多128个这一锁存器数是由CPU数决定的。

2K、4K、8K、16K、32K、KEEP、RECYCLE、DEFAULT 各使用16个锁存器,16*8=128个。



3、Buffer lock

如果说,cache buffers chains latch和cache buffers lru chains latch起到保护Hash Chain结构和工作组(LRU+LRUW)结构的作用,Buffer lock则起到保护缓存区自身的作用。欲修改或读取缓存区内容的进程,直到修改或读取工作结束为止,必须对相应缓存区以Exclusive或Shared模式取得Buffer lock。这是为了阻止两个进程同时修改缓冲区内容。


4、检索缓存区

oracle恰当使用Hash Chain和LRU、LRUW列,将用户请求的块移到高速缓存区。这个步骤和方法按照时间顺序整理后如下。
(1)对于用户请求的块DBA和类型利用Hash函数创建Hash值,然后检索Hash值相应的Hash bucket。
(2)获得保护Hash bucket的cache buffers chains latch锁存器。若是读取工作就以Shared模式获得锁存器;若是修改工作,就以Exclusive模式获得锁存器。如果在这个过程中发生争用,则等待latch: cache buffers chains事件。检索Hash bucket上的chain后,确认块相应Buffer Herder存在与否。如果Buffer Herder已经存在,并且相应块已经位于高速缓存区时,对相应缓存区以Shared模式或Exclusive模式获得Buffer Lock。然后执行所希望的工作。一般情况下,若在获得Buffer Lock过程中发生争用,则等待buffer busy waits事件。对正在通过DBWR写入的缓存区,在获得Buffer Lock过程中发生争用,则等待write complete waits事件。获得cache buffers chains latch锁存器后检索Hash Chain,为了使用缓存区,在获得Buffer Lock后执行读取缓存区一连串的工作,这就是Logical Reads。发生Logical Reads的块数量与session logical reads统计值的增量相同。若Logical Reads是一致性读取(consistent read)工作,则是consistent gets统计会增加;若是当前模式读取(current read)工作,则是db block gets统计值会增加。因此,session logical reads统计值就是consistent gets和db block gets的统计值之和。
(3)若高速缓存区上不存在块,将先获得管理工作组的cache buffers lru chains latch锁存器。这个工程中如果发生争用,则等待latch: cache buffers lru chain事件。获得锁存器后,在LRU列的辅助列上检索空闲缓存区。若辅助列没有可用的空闲缓存区,就在主列上按最少用的顺序检索空闲缓存区(在次过程中,如果发现脏缓存区,则将它移动到LRUW列),找到空闲缓存区后,对于相应缓存区以Exclusive模式获得buffer lock,并从数据文件将块读取到相应的缓存区。此时,在获得buffer lock过程中若发生争用,则等待read by other session事件。从数据文件物理的读取块的一连串的工作称为Physical Reads。发生Physical Reads的块数与physical reads统计值的增量相同。Physical Reads统计值在direct path I/O工作时也会增加,故经过高速缓存区的正确的物理读取值是从physical reads统计值上减去physical reads direct、physical reads direct (lob)统计值。
(4)LRU列上检索空间缓存区时,扫描与_DB_BLOCK_SCAN_MAX_PCT(缺省值是40)参数相同的LRU列部分后,若还没有找到空闲缓存区,则服务器进程将停止LRU列的扫描。服务器进程请求DBWR将脏缓冲区记录到数据文件里,以确保空闲缓存区。通过DBWR保证拥有空闲缓冲区为止,服务器进程将等待free buffer waits事件。收到请求的DBWR将增加 DBWR make free request统计值,在获得cache buffers lru chains latch锁存器后,从clod区域的尾部开始检索LRUW列。若找到想记录到磁盘上的缓存区,在获得buffer lock后记录到磁盘,而记录到磁盘上缓存区变更为空闲缓冲区,以移动到LRU列,每当DBWR检索LRUW列时,DBWR lru scans统计值和DBWR buffers scanned统计值就会增加。


5、高速缓存区转储(buffer chche dump)

就象实例中的其他内存结构一样,oracle提供了可以将buffer cache转储到跟踪文件的方法。方法如下:

ALTER SESSION SET EVENTS 'immediate trace name buffers level <level>';

这里的level有很多值,分别可以转储buffer cache中的不同的内容。level的可选值包括:


1 只转储buffer header


2 在level 1的基础上再转储数据块头


3 在level 2的基础上再转储数据块内容


4 转储buffer header和hash chain


5 在level 1的基础上再转储数据块头和hash chain


6 在level 2的基础上再转储数据块内容和hash chain


8 转储buffer header和hash chain以及users/waiters链表


9 在level 1的基础上再转储数据块头、hash chain以及users/waiters链表


10 在level 2的基础上再转储数据块内容、hash chain以及users/waiters链表


我们创建一个简单的测试表,然后看看转储出来的buffer header是什么样子的。


SQL> create table buffer_test(id number);  
  
表已创建。  
  
SQL> select object_id from dba_objects where object_name='BUFFER_TEST';  
  
 OBJECT_ID  
----------  
     73701  
  
SQL> insert into buffer_test values(1);  
  
已创建 1 行。  
  
SQL> commit;  
  
提交完成。

这时我们知道buffer_test表的object_id是73701,同时,该表中只有2个block具有数据。1个是segment header,另一个就是实际存放了1这个值的数据块。接着我们把buffer header转储出来:


SQL> ALTER SESSION SET EVENTS 'immediate trace name buffers level 1';  
      
    会话已更改。  
      
    SQL> select d.value || '/' || lower(rtrim(i.instance, chr(0))) || '_ora_' ||       --获取跟踪文件  
           p.spid || '.trc' trace_file_name  
      3    from (select p.spid  
      4           where m.statistic# = 1sys.v$session s, sys.v$process p  
              from sys.v$mystat m, sys.v$session s, sys.v$process p  
      5           where m.statistic# = 1  
      6             and s.sid = m.sid  
      7             and p.addr = s.paddr) p,  
      8         (select t.instance  
      9            from sys.v$thread t, sys.v$parameter v  
     10           where v.name = 'thread'  
     11             and (v.value = 0 or t.thread# = to_number(v.value))) i,  
     12         (select value from sys.v$parameter where name = 'user_dump_dest') d;  
      
    TRACE_FILE_NAME  
    --------------------------------------------------------------------------------  
    /u01/app/diag/rdbms/orcl/orcl/trace/orcl_ora_3817.trc

user_dump_dest所定义的目录下,找到跟踪文件并打开,可以看到类似下面的信息,这里我们列出前两个buffer header以及我们建立的object_id为73701的buffer_test表所对应的buffer header的内容:


BH (0x373f3b44) file#: 1 rdba: 0x00415116 (1/86294) class: 1 ba: 0x372ae000  
      set: 5 pool 3 bsz: 8192 bsi: 0 sflg: 3 pwc: 0,15  
      dbwrid: 0 obj: 420 objn: 422 tsn: 0 afn: 1 hint: f  
      hash: [0x397f4334,0x51bf8b14] lru: [0x43bf9634,0x3abf32d4]  
      ckptq: [NULL] fileq: [NULL] objq: [0x41bf0cd4,0x36bf0210]  
      st: XCURRENT md: NULL tch: 1  
      flags:  
      LRBA: [0x0.0.0] LSCN: [0x0.0] HSCN: [0xffff.ffffffff] HSUB: [65535]  
      cr pin refcnt: 0 sh pin refcnt: 0  
    `````````````````````````````````  
    BH (0x45ff59e8) file#: 1 rdba: 0x00415116 (1/86294) class: 1 ba: 0x45ef8000  
      set: 6 pool 3 bsz: 8192 bsi: 0 sflg: 3 pwc: 0,15  
      dbwrid: 0 obj: 420 objn: 422 tsn: 0 afn: 1 hint: f  
      hash: [0x51bf8b14,0x397f4334] lru: [0x397f4364,0x46beb770]  
      lru-flags: moved_to_tail on_auxiliary_list  
      ckptq: [NULL] fileq: [NULL] objq: [NULL]  
      st: FREE md: NULL tch: 0 lfb: 33  
      flags:  
      cr pin refcnt: 0 sh pin refcnt: 0  
    ``````````````````````````````````````````````````````````````````````  
    BH (0x39feb6c4) file#: 1 rdba: 0x00414df1 (1/85489) class: 1 ba: 0x39d6e000  
      set: 5 pool 3 bsz: 8192 bsi: 0 sflg: 3 pwc: 0,15  
      dbwrid: 0 obj: 73701 objn: 73701 tsn: 0 afn: 1 hint: f  
      hash: [0x51b36c64,0x51b36c64] lru: [0x3ebf9b2c,0x51473c30]  
      obj-flags: object_ckpt_list  
      ckptq: [0x51476178,0x36fe9b70] fileq: [0x5147618c,0x36fe9b78] objq: [0x4e8799b8,0x4e8799b8]  
      st: XCURRENT md: NULL tch: 1  
      flags: buffer_dirty redo_since_read  
      LRBA: [0xa0.cd9e.0] LSCN: [0x0.16c3ed] HSCN: [0x0.16c3ed] HSUB: [1]  
      cr pin refcnt: 0 sh pin refcnt: 0  
    `````````````````````````````````  
    BH (0x3d7f9588) file#: 1 rdba: 0x00414df0 (1/85488) class: 4 ba: 0x3d788000  
      set: 6 pool 3 bsz: 8192 bsi: 0 sflg: 3 pwc: 0,15  
      dbwrid: 0 obj: 73701 objn: 73701 tsn: 0 afn: 1 hint: f  
      hash: [0x51bc78b4,0x51bc78b4] lru: [0x447f4ad8,0x3efefdd4]  
      obj-flags: object_ckpt_list  
      ckptq: [0x36beada8,0x363ed710] fileq: [0x3fbe63fc,0x5147a41c] objq: [0x4e8dc24c,0x4e8dc24c]  
      st: XCURRENT md: NULL tch: 2  
      flags: buffer_dirty redo_since_read  
      LRBA: [0xa0.cd82.0] LSCN: [0x0.16c3d5] HSCN: [0x0.16c3ed] HSUB: [1]  
      cr pin refcnt: 0 sh pin refcnt: 0

我们可以看到第一个BH (0x373f3b44)的hash: [0x397f4334,0x51bf8b14]和第二个BH (0x45ff59e8)的hash: [0x51bf8b14,0x397f4334]。这里记录的就是指向前一个buffer header和后一个buffer header的指针。这里,我们看到第一个BH所指向的后一个buffer header的指针是0x51bf8b14,而第二个BH所指向的前一个buffer header的指针也是0x51bf8b14,说明这两个buffer header是在同一个hash chain上。同样的,我们还可以看到类似结构的lru、ckptq、fileq,这些都是管理buffer header的一些链表结构。


然后,我们来看我们创建的buffer_test表所对应的buffer header。 首先,我们看到class,表示该buffer header所对应的数据块的类型,具体的值与含义的对应为:1=data block;2=sort block;3=save undo block;4=segment header;5=save undo header;6=free list;7=extent map;8=1st level bmb;9=2nd level bmb;10=3rd level bmb;11=bitmap block;12=bitmap index block;13=unused;14=undo header;15=undo block。我们可以看到与buffer_test表相关buffer header有两个:一个是4(segment header),另一个是1(data block)。


然后,我们看到rdba,这表示buffer header所对应的数据块的地址。我们可以看到class为1的buffer header的rdba为0x00414df1 (1/85489)。说明该数据块的位置是1号文件的85489号block里。004表示数据文件号乘以4,而14df1表示数据块的号。

SQL> select to_number('004','xxx')/4 as file#,to_number('14df1','xxxxx') as block# from dual;  
  
     FILE#     BLOCK#  
---------- ----------  
         1      85489

我们看到,该buffer header指向的就是1号文件里的85489号数据块。我们可以再来看看表buffer_test 里的rowid所告诉我们的文件号以及数据块号,从下面可以看到,结果是一样的。


SQL> select id,  
       dbms_rowid.rowid_relative_fno(rowid) as file#,  
       dbms_rowid.rowid_block_number(rowid) as block#  
  4    from buffer_test;  
  
        ID      FILE#     BLOCK#  
---------- ---------- ----------  
         1          1      85489

我们可以来看一下st,这表示buffer cache所指向的数据块的状态。一共有六种状态:FREE(0)=可以被重用的数据块;XCURRENT(1)=实例以排他方式获取的当前模式数据块;SCURRENT(2)=可以与其他实例共享的当前模式数据块;CR(3)=作为一致性读镜像的数据块,永远不会被写入磁盘;READING(4)=正在从磁盘读出的数据块;MRECOVERY(5)=正在进行介质恢复的数据块;IRECOVERY(6)=正在进行实例恢复的数据块。从状态说明中我们可以看到,现在表buffer_test的数据块都是当前模式的数据块。另外,我们还可以看到tch,就是表示该数据块被扫描的次数。 以上这些是转储出来的内容。Oracle还提供了视图来显示buffer header的内容,这就是X$BH。这个视图就是把转储到平面文件以后所看到的诸如hash、st、tch等的值以列的方式呈现出来。这里就不做过多的介绍了,有兴趣的话,可以将该视图取出的结果与转储出来的文件进行比较,就可以知道每一列的含义。


SQL> desc x$bh;  
     名称                                      是否为空? 类型  
     ----------------------------------------- -------- ----------------------------  
     ADDR                                               RAW(4)  
     INDX                                               NUMBER  
     INST_ID                                            NUMBER  
     HLADDR                                             RAW(4)  
     BLSIZ                                              NUMBER  
     NXT_HASH                                           RAW(4)  
     PRV_HASH                                           RAW(4)  
     NXT_REPL                                           RAW(4)  
     PRV_REPL                                           RAW(4)  
     FLAG                                               NUMBER  
     FLAG2                                              NUMBER  
     LOBID                                              NUMBER  
     RFLAG                                              NUMBER  
     SFLAG                                              NUMBER  
     LRU_FLAG                                           NUMBER  
     TS#                                                NUMBER  
     FILE#                                              NUMBER  
     DBARFIL                                            NUMBER  
     DBABLK                                             NUMBER  
     CLASS                                              NUMBER  
     STATE                                              NUMBER  
     MODE_HELD                                          NUMBER  
     CHANGES                                            NUMBER  
     CSTATE                                             NUMBER  
     LE_ADDR                                            RAW(4)  
     DIRTY_QUEUE                                        NUMBER  
     SET_DS                                             RAW(4)  
     OBJ                                                NUMBER  
     BA                                                 RAW(4)  
     CR_SCN_BAS                                         NUMBER  
     CR_SCN_WRP                                         NUMBER  
     CR_XID_USN                                         NUMBER  
     CR_XID_SLT                                         NUMBER  
     CR_XID_SQN                                         NUMBER  
     CR_UBA_FIL                                         NUMBER  
     CR_UBA_BLK                                         NUMBER  
     CR_UBA_SEQ                                         NUMBER  
     CR_UBA_REC                                         NUMBER  
     CR_SFL                                             NUMBER  
     CR_CLS_BAS                                         NUMBER  
     CR_CLS_WRP                                         NUMBER  
     LRBA_SEQ                                           NUMBER  
     LRBA_BNO                                           NUMBER  
     HSCN_BAS                                           NUMBER  
     HSCN_WRP                                           NUMBER  
     HSUB_SCN                                           NUMBER  
     US_NXT                                             RAW(4)  
     US_PRV                                             RAW(4)  
     WA_NXT                                             RAW(4)  
     WA_PRV                                             RAW(4)  
     OQ_NXT                                             RAW(4)  
     OQ_PRV                                             RAW(4)  
     AQ_NXT                                             RAW(4)  
     AQ_PRV                                             RAW(4)  
     OBJ_FLAG                                           NUMBER  
     TCH                                                NUMBER  
     TIM                                                NUMBER  
     CR_RFCNT                                           NUMBER  
     SHR_RFCNT                                          NUMBER



6、buffer cache 优化

从8.0以后,oracle提供了三种类型的buffer cache,分别是default、keep、recyle。keep和recycle是可选的,default必须存在。通常将经常访问的对象放入keep类型的buffer cache里,而将不常访问的大表放入recycle类型的buffer cache里。其他没有指定buffer cache类型的对象都将进入default类型的buffer cache里。如果没有指定buffer_pool短语,则表示该对象进入default类型的buffer cache。

这里要说明的是,从名字上看,很容易让人误以为这三种buffer cache提供了三种不同的管理内存数据块的机制。但事实上,它们之间在管理和内部机制上没有任何的区别。它们仅仅是为DBA们提供了一个选择,就是能够将数据库对象分成“非常热的”、“比较热的”和“不热的”这三种类型。因为数据库中总会存在一些“非常热”的对象,它们频繁的被访问。而如果某个时候系统偶尔做了一次大表的全表扫描,就有可能将这些对象清除出内存。为了防止这种情况的发生,我们可以设置keep类型的buffer cache,并将这种对象都移入keep buffer cache中。同样的,数据库中也总会有一些很大的表,可能每天为了生成一张报表,而只需要访问一次就可以了。但有可能就是这么一次访问,就将大部分的内 存数据块清除出了buffer cache。为了避免这种情况的发生,可以设置recycle类型的buffer cache,并将这种偶尔访问的大表移入recycle buffer cache。

毫无疑问,如果你要设置这三种类型的 buffer cache,你需要自己研究并等于你的数据库中的对象进行分类,并计算这些对象的大小,从而才能够正确的把它们放入不同的buffer cache。但是,不管怎么说,设置这三种类型的buffer cache只能算是最低层次的优化,也就是说在你没有任何办法的情况下,可以考虑设置他们。但是如果你能够优化某条buffer gets非常高SQL使其buffer gets降低50%的话,就已经比设置多个buffer cache要好很多了。

9i以后还提供了可以设置多种数据块尺寸(2、4、8、16 或 32k)的buffer cache,以便存放不同数据块尺寸的表空间中的对象。OLTP环境下,倾向于使用较小的数据块,而OLAP环境下,由于基本 都是执行全表扫描,因此倾向于使用较大的数据块。

7、总结

granule:Buffer Cache、Shared Pool、Large Pool和Java Pool(在10g中,还包括Streams Pool、KEEP buffer cache、RECYCLE buffer cache、nK Buffer Cache、ASM Buffer Cache)的增长和收缩都是以granule为单位的。当SGA小于128M时,granule为4M,SGA大于128M时,granule为16M。

chunk:从一个物理的层面来看,shared pool是由许多内存块组成,这些内存块通常称为chunk。Chunk是shared pool中内存分配的最小单位,一个chunk中的所有内存都是连续的。在shared pool里,可用的chunk(free类型)会被串起来成为可用链表(free lists)或者也可以叫做buckets(一个可用链表也就是一个bucket)。
handle:Handle对实际LCO起到meta信息和指针作用,LCO保存着实际信息。
lco:Library Cache Object,LCO所包含的重要信息有:当前LCO依赖其它LCO的信息、关于当前LCO的子LCO的信息、LCO包含的实际信息(数据)所存储的chunk区域的指针信息。

bucket:每个空闲的chunk(大块)都会属于也只属于一个空闲列表(free list)。空闲列表上的chunk的大小范围是由bucket来划分的。Bucket直译为“桶”,在西方,往往用桶来盛装一定品质范围的物品,以便查找。比如,在采矿时,用不同的桶来装不同纯度的矿石,在桶上标明矿石的纯度范围,以便在提炼时可以采用不同工艺。在这里,我们也可以把bucket视为一种索引,使Oracle在查找空闲块时,先定位所需的空闲块在哪个bucket的范围内,然后在相应的空闲列表中查找。
buffer header:与数据块一一对应,buffer header 里记录的数据块地址和数据块类型。Buffer Header拥有对于缓冲区的Meta信息,并拥有缓存区区域实际缓冲区的指针值。buffer header位于共享池内。
buffer:也是与数据块一一对应,buffer里记录的数据块的实际内容。buffer位于高速缓存区。