buffer cache中的LRU链+

转自晶晶小妹的博客:http://space.itpub.net/13095417/viewspace-204007

一、LRU链介绍
HASH是快速查找时,常用的算法。Oracle中几乎在所有需要快速查找的地方,都使用了HASH算法。LRU则是在“资源重用”时,常用的算法。
       在Buffer
cache中,LRU链被分为两半,分别是热端、冷端,在默认方式下,热、冷端各占50%的块,这点可以由隐藏参数_db_percent_hot_default控制。当块第一次被读进Buffer时,会被插入到冷端头位置处。每次需要自由块时,Oracle服务器进程从冷端尾开始搜索可以被重用的块,因此,冷端的块是最有可能被重用的。在每个块的Buffer
header中,准备有一个量,记录块被访问的次数,称作:Touch Count(TCH)。它代表块的访问频率。Oracle通过它决定块的冷热位置。在DSI中,专门有一段伪码,介绍TCH和块的重用:

关于Touch Count值具体算法如下:
IF ( 当前块的touch
count 数> _db_aging_hot_criteria ) THEN
    此块暂不重用

IF (_db_aging_stay_count >= _db_aging_hot_criteria) THEN
        将此块的Touch
Count数减半

ELSE

将此块的Touch Count值传给_db_aging_stay_count

END IF
ELSE

    此块将被重用
END IF
(上述伪码来自DSI)
       其中,_db_aging_hot_criteria与_
db_aging_stay_count都是Oracle的隐含参数,_db_aging_hot_criteria值默认为2,_
db_aging_stay_count有可能会随时变化。
       根据这段代码,假如说,又有新的物理读发生了,Buffer
cache中已经没有了空块,服务器进程开始从LRU的冷端开始扫描,寻找可以被重用的自由块。
例如,LRU冷端第一个块的TCH值为4,而当前_db_aging_hot_criteria参数仍为默认值2。因为块的TCH为4,大于2,此块暂不重用。假如_db_aging_stay_count当前值为0,_db_aging_stay_count并不大于等于_db_aging_hot_criteria,因此,将此块的Touch
Count值传给_db_aging_stay_count,当前_db_aging_stay_count的值变为了4。
       第一个块不可重用,继续向后查找。假如第二个块的TCH也为4,跟据上面的算法,它也不会被重用,但此时由于_db_aging_stay_count的值已经变为了4,已经大于_db_aging_hot_criteria的值2,因此,此块的TCH值将被减半,变为2。
       等等,服务器进程照此算法扫描LRU上的块,直到找到足够的自由块为止。
       但是这段伪码和我试验的结果一直不符。我试验的结果,每当块的TCH值发生变化时,并不会立即改变它所处的位置。块一旦从冷端移到了热端,TCH值马上变为0。
具体是,服务器进程需要读块进Buffer,它会从LRU链的尾端开始搜索自由块,如果发现搜索到的块的TCH值小于2,就重用这个块,并把它移动到冷端头。如果发现TCH大于2的块,并不会重用它,而是把它移到热端头部,并把它的TCH设为0。下面,我们试验一下这个过程:

步1:改变12号文件7号块的TCH值:
先确定一下,此块目前并不在Buffer cache中:
SQL> select lru_flag,tch from x$bh where dbablk=12 and dbarfil=7;

未选定行
然后,通过ROWID显示12号文件7号块中的任意一行。(可以只接用ROWID作为条件,也可以使用索引)
SQL> select id from jj_1 where rowid='AAAMt2AAHAAAAAMAAA';

ID
---------- 
1

再看一下12号文件7号块的TCH值:
SQL> select lru_flag,tch from x$bh where dbablk=12 and dbarfil=7;

LRU_FLAG   TCH

----------    ----------
0        1

已经是1了。LRU_FLAG列是此块目前在LRU链表中的位置。当此值为8或9时,代表块已经被送进热端。
此时,12号文件7号块当前被添加到了11的位置处:


热 
        端


冷 
        端


1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19


20


12/7

TCH:1

每隔三秒,重复执行9遍如下命令:
SQL> select id from jj_1 where rowid='AAAMt2AAHAAAAAMAAB';
ID
----------
8

此时12号文件7号块的TCH值应该已经是10了,再显示一下:
SQL> select lru_flag,tch from x$bh where dbablk=12 and dbarfil=7;
LRU_FLAG  TCH
---------- ----------
0     10
可以看到,已经是10了。但是,LRU_FLAG列仍是0。块并不会被移动到热端。
此时12号文件7号块的情况如下:


热 
        端


冷 
        端


1


2


3


4


5


6


7


8


9


10


11


12


13


14


15


16


17


18


19


20


12/7

TCH:10

除TCH变为10外,12号文件7号块并不会被移到热端。

[ 本帖最后由 晶晶小妹 于 2008-3-11 21:04 编辑 ]

晶晶小妹 发布于2008-03-11
21:01:53
步2:在另一个表以索引方式扫描若干行:
SQL> select /*+index(qsmed.zjj1) */ * from qsmed.zjj1 where id>=1750 and id<=3500;
已选择1751行。

执行计划
----------------------------------------------------------
Plan hash value: 2538640105
---------------------------------------------------------------------------------------
| Id  | Operation                   | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |         |  1772 |   164K|    31   (0)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| ZJJ1    |  1772 |   164K|    31   (0)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | ZJJ1_ID |  1772 |       |     6   (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ID">=1750 AND "ID"<=3500)
统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
        263  consistent gets
         25  physical reads
          0  redo size
     165015  bytes sent via SQL*Net to client
       1661  bytes received via SQL*Net from client
        118  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
       1751  rows processed
这有25个物理读。为了为这25个物理读寻找可用块,服务器进程将从LRU的末端,寻找可用块,将ZJJ1相关的块的信息覆盖这些可用块。并将它们从LRU的冷端末尾,移到冷端头。
显示12号文件7号块,不会有任何变化:
SQL> select lru_flag,tch from x$bh where dbablk=12 and dbarfil=7;
  LRU_FLAG        TCH                                                           
---------- ----------                                                           
         0         10                                                           
ZJJ1的25个物理读,目前还没有对12号文件7号块的状态有任何的影响,只不过,12号文件7号块被挤了向冷端末尾:


热 
        端


冷 
        端


1


2


3


4


5


6


7


8


9


10


17


18


19


20


11


12


13


14


15


16


12/7

TCH:10


ZJJ_1


JJ_1

上图中ZJJ_1只占了4个格,这是不精确的,ZJJ_1和其索引应该占至少25个块才对,因为物理读有25个块。

[ 本帖最后由 晶晶小妹 于 2008-3-11 21:07 编辑 ]

晶晶小妹 发布于2008-03-11
21:02:40
步3:进一步加大从ZJJ_1扫描的行数:
SQL> select /*+index(qsmed.zjj1) */ * from qsmed.zjj1 where id<=7000;
已选择7000行。

执行计划
----------------------------------------------------------
Plan hash value: 2538640105
---------------------------------------------------------------------------------------
| Id  | Operation                   | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |         |  7060 |   654K|   116   (1)| 00:00:01 |
|   1 |  TABLE ACCESS BY INDEX ROWID| ZJJ1    |  7060 |   654K|   116   (1)| 00:00:01 |
|*  2 |   INDEX RANGE SCAN          | ZJJ1_ID |  7060 |       |    18   (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ID"<=7000)
统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
       1034  consistent gets
         50  physical reads
          0  redo size
     668076  bytes sent via SQL*Net to client
       5511  bytes received via SQL*Net from client
        468  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
       7000  rows processed
显示12号文件7号块,不会有任何变化:
SQL> select lru_flag,tch from x$bh where dbablk=12 and dbarfil=7;
  LRU_FLAG        TCH                                                           
---------- ----------                                                           
         0         10                                                           
当前的状态可以近似的用如下的图表示:


热 
        端


冷 
        端


1


2


3


4


5


6


7


8


9


10


12


13


14


15


16


17


18


19


20


11


12/7

TCH:10


ZJJ_1


JJ_1

步4:再加大扫描的行数:
SQL> select /*+index(qsmed.zjj1) */ * from qsmed.zjj1 where id<=17500;
已选择17500行。

执行计划
----------------------------------------------------------
Plan hash value: 2538640105
---------------------------------------------------------------------------------------
| Id  | Operation                   | Name    | Rows  | Bytes | Cost (%CPU)| Time     |
---------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |         | 17683 |  1640K|   287   (1)| 00:00:02 |
|   1 |  TABLE ACCESS BY INDEX ROWID| ZJJ1    | 17683 |  1640K|   287   (1)| 00:00:02 |
|*  2 |   INDEX RANGE SCAN          | ZJJ1_ID | 17683 |       |    42   (0)| 00:00:01 |
---------------------------------------------------------------------------------------
Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("ID"<=17500)
统计信息
----------------------------------------------------------
          1  recursive calls
          0  db block gets
       2589  consistent gets
        116  physical reads
          0  redo size
    1794670  bytes sent via SQL*Net to client
      13211  bytes received via SQL*Net from client
       1168  SQL*Net roundtrips to/from client
          0  sorts (memory)
          0  sorts (disk)
      17500  rows processed
这一次12号文件7号块的位置和状态发生了变化,
SQL> select lru_flag,tch from x$bh where dbablk=12 and dbarfil=7;
  LRU_FLAG        TCH                                                           
---------- ----------                                                           
         8          0                                                           
LRU_FLAG的值变为了8,TCH列被清零。这说明12号文件7号块被移到了热端。原来方格10所代表的块不再属于热端,已被挤到了冷端。


热 
        端


冷 
        端


11


1


2


3


4


5


6


7


8


9


10


12


13


14


15


16


17


18


19


20


12/7

TCH:0


JJ_1


ZJJ_1

时间: 2024-09-07 23:37:25

buffer cache中的LRU链+的相关文章

揭密Oracle之七种武器之四:揭密Buffer Cache中的链表

有日子没写东西了.又是看房又是讲课,好多朋友问我是不是不写了,怎么会呢,分享知识,也是自我总结的一个过程,对自己的提高也是有帮助的吧. 前段时间,一直有人问我Buffer Cache的链表,LRU.辅助LRU.检查点队列等等.检查点队列已经有很多文章讨论过了,我就不再重复的制造轮子 .  另外,还有主LRU冷热端的相关内容,这一块我也不再详细描述,因为也有相关的文章. 我主要说一下主LRU.辅助LRU和LRUW相关的内容. 本篇文章没有使用DTrace和GDB,难度较低,但实验内容较多.我先将结

如何转储数据文件和Buffer Cache中的数据块

这篇文章是为了补充<Oracle性能优化与诊断案例精选>一书中的案例而写的,但是想想,也许还可以扩展一下,对于刚接触 Oracle 数据库的朋友们,试着回答一下以下几个问题,看看自己能否找到正确的答案: 当我们 insert 一条记录,不提交,这个数据在内存还是磁盘? 当我们 insert 一条记录,提交,这个数据在内存还是磁盘? 当我们 insert 一条记录,不提交,检查点,这个数据在内存还是磁盘? 当我们 insert 一条记录,提交,检查点,这个数据在内存还是磁盘? 先看看我的测试:

如何使用events DUMP buffer cache中指定的数据块

介绍了DUMP  buffer cache中全部数据块及指定RDBA的数据块方法. 1.DUMP  buffer cache中全部数据块 ALTER SESSION SET EVENTS 'immediate trace name buffers level n'; 1 buffer header 2 level 1 + block header 3 level 2 + block contents 4 level 1 + hash chain 5 level 2 + hash chain 6

buffer cache实验3:lru和lruw链表

1.Buffer cache中的LRU链表概念: oracle在hash chain中未搜索到所需要的buffer时,ORACEL 服务进程会发出I/O调用,到磁盘的数据文件中读取相应数据块--除了直接路径读外,此时会将数据块的内容拷贝到buffer cache 内存中--同时会构造一个buffer header. 在将数据块拷贝到buffer cache中时,假如buffer cache是空的,直接拿一个空的内存数据块来用即可. 但是如果buffer cache中的内存数据块全都被用掉了,没有

buffer cache实验6:latch:cache buffers lru chains

1.working set与Latch:cache buffers lru chain: 每个working set都具有它自己的一组LRU和LRUW链表(LRU和LRUW链表总是成对出现的). ORACLE为了提高buffer cache性能(大内存),使用了多个working set 每个working set都由一个名为"Latch:cache buffers lru chain"的latch来保护,每一个lru latch对应一个working set. 而每个被加载到buff

buffer cache实验9:从buffer caceh中读取数据块解析-从逻辑读到物理读

先来张大图: 所用SQL语句: BYS@ ocm1>select dbms_rowid.rowid_relative_fno(rowid) file#,dbms_rowid.rowid_block_number(rowid) block#,deptno from bys.test;     FILE#     BLOCK#     DEPTNO ---------- ---------- ----------         4        391         10 就以上图为例,文字描述

oracle中如何设置buffer cache

buffer cache的设置随着Oracle版本的升级而不断变化.Oracle 8i下使用db_block_buffers来设置,该参数表示buffer cache中所能够包含的内存数据块的个数:Oracle 9i以后使用db_cache_size来设置,该参数表示buffer cache的总共的容量,可以用字节.KB.MB为单位来进行设置.而到了Oracle 10g以后则更加简单,甚至可以不用去单独设置buffer cache的大小.因为Oracle 10g引入了ASMM(Automatic

Linux中Buffer cache性能问题解析

1, Buffer cache的作用 为了提高磁盘设备的IO性能,我们采用内存作为磁盘设备的cache.用户操作磁盘设备的时候,首先将数据写入内存,然后再将内存中的脏数据定时刷新到磁盘.这个用作磁盘数据缓存的内存就是所谓的buffer cache.在以前的Linux系统中,有很完善的buffer cache软件层,专门负责磁盘数据的缓存.在磁盘设备的上层往往会架构文件系统,为了提高文件系统的性能,VFS层同样会提供文件系统级别的page cache.这样就导致系统中存在两个cache,并且重叠在

buffer cache实验2:详解Buffer Header--DUMP buffer结合X$BH视图

Buffer Header结构图及简介 图1: buffer header:每一个数据块在被读入buffer cache时,都会先在buffer cache中构造一个buffer header,buffer header与数据块一一对应.buffer header包含的主要信息有: 1) 该数据块在buffer cache中实际的内存地址.就是上图中的虚线箭头所表示的意思. 2) 该数据块的类型,包括data.segment header.undo header.undo block等等. 3)