LRU是Buffer Cache池中的重要链表,它的作用我不再详述,已经有很多相关资料。这次主要和大家讨论下主LRU、辅助LRU的作用。

先来看一个测试。

步1:环境介绍

先来看看Buffer Cache的大小:

SQL> show sga

Total System Global Area 1073741824 bytes

Fixed Size                  1284344 bytes

Variable Size             960497416 bytes

Database Buffers          104857600 bytes

Redo Buffers                7102464 bytes

Buffer Cache大小100M。

再来看看测试表大小:

SQL> set linesize 1000

SQL> col segment_name for a30

SQL> SQL> select segment_name,bytes/1024/1024 from dba_segments where segment_name='A3_70M';

SEGMENT_NAME                   BYTES/1024/1024

------------------------------ ---------------

A3_70M                                      80

SQL> SQL> select segment_name,bytes/1024/1024 from dba_segments where segment_name='A4_70M';

SEGMENT_NAME                   BYTES/1024/1024

------------------------------ ---------------

A4_70M                                      80

两张测试表,A3_70M、A4_70M,各自大小80M。本来是想把它们两个大小建为70M的,所以名字带有后缀_70M,但建的大了一点,不过,这无所

谓,不会影响我们的测试结果。

步2:刷新Buffer Cache池,观察LRU链长度

SQL> alter system flush buffer_cache;

SQL> select CNUM_SET,CNUM_REPL,ANUM_REPL,CNUM_WRITE ,ANUM_WRITE  from x$kcbwds;

CNUM_SET  CNUM_REPL  ANUM_REPL CNUM_WRITE ANUM_WRITE

---------- ---------- ---------- ---------- ----------

0          0          0          0          0

0          0          0          0          0

0          0          0          0          0

0          0          0          0          0

6238       6238       6219          0          0

6237       6237       6224          0          0

0          0          0          0          0

0          0          0          0          0

0          0          0          0          0

0          0          0          0          0

0          0          0          0          0

CNUM_SET  CNUM_REPL  ANUM_REPL CNUM_WRITE ANUM_WRITE

---------- ---------- ---------- ---------- ----------

0          0          0          0          0

0          0          0          0          0

0          0          0          0          0

0          0          0          0          0

0          0          0          0          0

16 rows selected.

这个视图返回16行,但只有两行有数据。其他行都是0,原因是什么?

查一下select name from v$latch_children where name ='cache buffers lru chain'; 就可以知道,我一共有16个cache buffers lru

chain Latch,但只有两个被使用了。

每一个cache buffers lru chain latch,都算作一个“工作组”,work set。意义是指每个cache buffers lru chain latch,都对应一组主

、辅LRU链,和脏LRU链。

x$kcbwds视图中CNUM_SET列,统计工作组所有块数量。简单点说,也就是LRU链上所有块的数量。

CNUM_REPL列是主、辅LRU链表中所有的块数。

ANUM_REPL列是辅LRU链上所有的块数。

用CNUM_REPL-ANUM_REPL,即为所有主LRU链上的块数。

CNUM_WRITE、ANUM_WRITE这个列对应LRUW(也即为脏LRU)链,CNUM_WRITE为LRUW链中所有块数,ANUM_WRITE为辅助LRUW中的块数。两个相减,

要以得到主LRUW中的块数。

这个测试中,先不用观察LRUW。我们先只关注主、辅LRU。

来看我们的显示结果吧,两个工作组加起来,一共12475个块。

另外,可以看到,CNUM_REPL的ANUM_REPL列的几乎相等,这说明绝大多数块,都在辅助LRU链表中,这是为什么呢?这是我们今天第一点结论,

flush了buffer cache、或刚刚开启数据库时,所有的可用Buffer都会链接到辅助LRU中。

步3:先查询a3_70M,再查询a4_70M,分别观察物理读。(注意顺序,先查询A3_70M,再查询A4_70M)

SQL> set autot trace

SQL> select count(*) from a3_70m;

Execution Plan

----------------------------------------------------------

Plan hash value: 850873958

---------------------------------------------------------------------

| Id  | Operation          | Name   | Rows  | Cost (%CPU)| Time     |

---------------------------------------------------------------------

|   0 | SELECT STATEMENT   |        |     1 |  1643   (1)| 00:00:20 |

|   1 |  SORT AGGREGATE    |        |     1 |            |          |

|   2 |   TABLE ACCESS FULL| A3_70M |  1511K|  1643   (1)| 00:00:20 |

---------------------------------------------------------------------

Statistics

----------------------------------------------------------

207  recursive calls

0  db block gets

9292  consistent gets

9271  physical reads

0  redo size

414  bytes sent via SQL*Net to client

381  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

4  sorts (memory)

0  sorts (disk)

1  rows processed

SQL> select count(*) from a4_70m;

Execution Plan

----------------------------------------------------------

Plan hash value: 2047399966

---------------------------------------------------------------------

| Id  | Operation          | Name   | Rows  | Cost (%CPU)| Time     |

---------------------------------------------------------------------

|   0 | SELECT STATEMENT   |        |     1 |  1643   (1)| 00:00:20 |

|   1 |  SORT AGGREGATE    |        |     1 |            |          |

|   2 |   TABLE ACCESS FULL| A4_70M |  1502K|  1643   (1)| 00:00:20 |

---------------------------------------------------------------------

Statistics

----------------------------------------------------------

207  recursive calls

0  db block gets

9292  consistent gets

9259  physical reads

0  redo size

414  bytes sent via SQL*Net to client

381  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

4  sorts (memory)

0  sorts (disk)

1  rows processed

可以看到,第一次查询A3_70M和A4_70M,物理读分别是9200多。

步4:再次查询a3_70M,再查询a4_70M,分别观察物理读。(顺序无所谓,先查谁都可以)

SQL> select count(*) from a3_70m;

Execution Plan

----------------------------------------------------------

Plan hash value: 850873958

---------------------------------------------------------------------

| Id  | Operation          | Name   | Rows  | Cost (%CPU)| Time     |

---------------------------------------------------------------------

|   0 | SELECT STATEMENT   |        |     1 |  1643   (1)| 00:00:20 |

|   1 |  SORT AGGREGATE    |        |     1 |            |          |

|   2 |   TABLE ACCESS FULL| A3_70M |  1511K|  1643   (1)| 00:00:20 |

---------------------------------------------------------------------

Statistics

----------------------------------------------------------

0  recursive calls

0  db block gets

9269  consistent gets

213  physical reads

0  redo size

414  bytes sent via SQL*Net to client

381  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

1  rows processed

SQL> select count(*) from a4_70m;

Execution Plan

----------------------------------------------------------

Plan hash value: 2047399966

---------------------------------------------------------------------

| Id  | Operation          | Name   | Rows  | Cost (%CPU)| Time     |

---------------------------------------------------------------------

|   0 | SELECT STATEMENT   |        |     1 |  1643   (1)| 00:00:20 |

|   1 |  SORT AGGREGATE    |        |     1 |            |          |

|   2 |   TABLE ACCESS FULL| A4_70M |  1502K|  1643   (1)| 00:00:20 |

---------------------------------------------------------------------

Statistics

----------------------------------------------------------

0  recursive calls

0  db block gets

9269  consistent gets

9135  physical reads

0  redo size

414  bytes sent via SQL*Net to client

381  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

1  rows processed

发现没有,A3_70M的物理读在第二次查询时大量下降,只有213次。而A4_70M在第二次查询时,物理读下降很不明显,还是9200次左右。

可以再测个几遍,情况依旧。A3_70M的物理读很少,而A4_70M的物理读很多。

这是我们今天的问题一:考虑这是为什么。

下面继续我们的问题2。

步5:连续两次查询A3_70M和A4_70M

SQL> select count(*) from a4_70m;

Statistics

----------------------------------------------------------

0  recursive calls

0  db block gets

9269  consistent gets

8686  physical reads

0  redo size

414  bytes sent via SQL*Net to client

381  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

1  rows processed

SQL> select count(*) from a4_70m;

Statistics

----------------------------------------------------------

0  recursive calls

0  db block gets

9269  consistent gets

8722  physical reads

0  redo size

414  bytes sent via SQL*Net to client

381  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

1  rows processed

这是两次A4_70M的结果对比,多次查询A4_70M之后,物理读下降到了8700多,然后不再下降。

再来看两次连续查询A3_70M的结果对比:

SQL> select count(*) from a3_70m;

Statistics

----------------------------------------------------------

0  recursive calls

0  db block gets

9269  consistent gets

600  physical reads

0  redo size

414  bytes sent via SQL*Net to client

381  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

1  rows processed

SQL> select count(*) from a3_70m;

Statistics

----------------------------------------------------------

0  recursive calls

0  db block gets

9269  consistent gets

0  physical reads

0  redo size

414  bytes sent via SQL*Net to client

381  bytes received via SQL*Net from client

2  SQL*Net roundtrips to/from client

0  sorts (memory)

0  sorts (disk)

1  rows processed

第一次有600次物理读,第二次就没有了。

问题2出来了,考虑这是没什么。

步6:暂时总结

1、A3_70M和A4_70M表大小一样。行数一样、所占空间也一样,都是80M

2、第一次查询时,我们是先查询A3_70M,再查A4_70M。如果你反过来,先查A4_70M,将看到A4_70M的物理读在第二次查询时大大减少,连续两

次查询时物理读为0。

两个问题:

1、为什么第一次查询时,先查的表,在第二次查询时物理读会大大减少,而后查的表则不会。

2、为什么第一次查询时,先查的表连续两次查询时物理读会减少为0,而后查的表不会。

一个提示:可以观察一下我们开始提到的x$kcbwds视图。

步7:如何观察块处在哪个链上。

如何进一步分析这个问题?其实这两个问题的回答,都需要着落到一件事上,就是要分析两个表对应的块,分别在什么链上。是在主LRU,还是

辅LRU。如何进行这个观察呢?其实很简单,x$bh中有个LRU_FLAG列,通过这个列,就可以确定块在哪个链表上。

我们来看一下这个视图:

SQL> select lru_flag,count(*) from x$bh group by lru_flag;

LRU_FLAG   COUNT(*)

---------- ----------

6       3081

2       6734

8          2

0       2658

在我的测试库中,我观察到的LRU_FLAG有4种值,6、2、8和0。这4个值分别代别什么意义呢?确定这个其实很简单,DUMP一下块对应的Buffer

就行了,以LRU_FLAG为6的为例:

(1)、随便查找LRU_FLAG为6的一行:

SQL> select lru_flag,file#,dbablk,TS# from x$bh where LRU_FLAG=6 and rownum=1;

LRU_FLAG      FILE#     DBABLK        TS#

---------- ---------- ---------- ----------

6          5      12459          4

(2)、如下DUMP一下这个BUffer:

SQL> alter session set events 'immediate trace name SET_TSN_P1 level 5';

Session altered.

SQL> alter session set events 'immediate trace name BUFFER level 0x014030ab';

Session altered.

上面这两个命令,“SET_TSN_P1 level 5”中的5,是表空间号加1得到的。也就是TS#+1。

第二个命令中“BUFFER level 0x014030ab”,其中0x014030ab,是5号文件12459号块的DBA。

这个DBA是如何计算出的?其实我是在另一个会话中DUMP一下5号文件12459号块,查看DUMP结果才得到的,Oracle也提供了一个包,其实有个函

数可以根据文件号、块号生成DBA,包名、函数名我都忘了,只好用笨方法。

好,来查看DUMP结果吧,到user_dump_dest目录中,找到日期最靠后的(我一般是ls -lFrt),它就是我们刚刚生成的DUMP文件。在它的开头,

我们可以看到如下内容:

*** 2012-07-03 08:58:36.571

*** SERVICE NAME

SYS$USERS) 2012-07-03 08:58:36.523

*** SESSION ID

874.3) 2012-07-03 08:58:36.523

Dump of buffer cache at level 10 for tsn=4, rdba=20983979

BH (7bbf0764) file#: 5 rdba: 0x014030ab (5/12459) class: 1 ba: 7b9dc000

set: 5 blksize: 8192 bsi: 0 set-flg: 0 pwbcnt: 0

dbwrid: 0 obj: 9738 objn: 9738 tsn: 4 afn: 5

hash: [7d7e687c,8e94b67c] lru: [7bbe80b8,7bbf0704]

lru-flags: moved_to_tail on_auxiliary_list

ckptq: [NULL] fileq: [NULL] objq: [7bbf075c,7bbe8110]

st: XCURRENT md: NULL tch: 0

flags: only_sequential_access

LRBA: [0x0.0.0] HSCN: [0xffff.ffffffff] HSUB: [65535]

buffer tsn: 4 rdba: 0x014030ab (5/12459)

scn: 0x0000.00418edb seq: 0x01 flg: 0x06 tail: 0x8edb0601

frmt: 0x02 chkval: 0xc400 type: 0x06=trans data

我对这里面的东西,不过多解释了,其实有一行:

lru-flags: moved_to_tail on_auxiliary_list

这一行说明了块对应Buffer所在LRU链表的状态。Buffer目前在辅助LUR,moved_to_tail说明Buffer正移向链表末尾。

好了,我们已经总结出来,LRU_FLAG列为6,说明Buffer在辅助LRU链表。

其他的我不再一一列出测试过程了,总结一下,LRU_FLAG为6、4,说明BUffer在辅助LRU中。为0、2,说明在主LRU的冷端,为8、9的,说明在

主LRU的热端。

步8:问题1:为什么第一次查询时,先查的表,在第二次查询时物理读会大大减少,而后查的表则不会

让我们来观察一下A3_70M、A4_70M 的块都在什么链上

SQL> select lru_flag,count(*) from x$bh a,dba_objects b where a.obj=b.data_object_id and object_name='A3_70M' group by lru_flag;

LRU_FLAG   COUNT(*)

---------- ----------

2       8554

0          1

SQL> select lru_flag,count(*) from x$bh a,dba_objects b where a.obj=b.data_object_id and object_name='A4_70M' group by lru_flag;

LRU_FLAG   COUNT(*)

---------- ----------

6       3082

2        366

0          1

这两条语句,我就不再过多解释了,根据LRU_FLAG列的值,我们可以确认,A3_70M,共有8555个块在Buffer Cache中,所有相关的块都在主LRU

链。A4_70M,只有3400多个块在Buffer Cache中,而且大部分块都在辅助LRU。

为什么A3_70M的块,被读进Buffer Cache时,大多被放置在主LRU的冷端?而A4_70M的块,则被放进辅助LRU呢?

能回答这个问题,我们今天的问题也就有了答案。

步9:回答问题1

有如下三点基础知识:

1、当数据库刚刚打开、或刚刚做过FLush Buffer_cache操作时,所有的块,都被放进辅助LRU。

2、进程寻找可用块时,先会在辅助LRU中查找,然后才会到主LRU中找。

3、Oracle会保持20%至25%左右的块在辅助LRU链,80%的在主LRU。这一点,从观察x$kcbwds中的CNUM_REPL、ANUM_REPL列,可以很容易的验证

有了这三点基础知识,让我们来得出结论吧:

当所有块都在辅助LRU时,Oracle为了急于保证主、辅LRU,块数量80%,20%的比例,第一次查询时,会将大量的块移到主LRU。也就是说,第一

次查询A3_70M时,大至步骤是这样的,分两种情况:

一、主LRU几乎为空时:

1、在辅助LRU找到可用块。

2、将它移到主LUR

3、将数据读入此块。

二、当主、辅LRU的块数量比例到达80%、20%后

1、在辅助LRU找到查用块

2、所处链表不变,直接将数据读入此块。

3、物理读完成后,块还在辅助LRU中。

由于第一次查询A3_70M时,主LRU几乎为空,所以,它的绝大部分的块被放在了主LRU,少部分块被放入了辅助LRU。

根据比例,辅助LRU中将会有3000到3200个左右的块。根据我们的测试结果,全表扫描A4_70M后,有3000多个块在辅助链上。根据这个,得出我

们今天第二个结论,正常的全表扫描操作,将只会反复使用辅助LRU中的块。

当然,我们的测试中,还是有少量A4_70M的块进入到了主LRU,不过数量不多,只有几百个。

好了,回答一开始的问题吧,第一次查询A3_70M,Oracle会了保持主、辅LRU的比例,将很多被A3_70M占用的块移进了主LRU,所以,A3_70M在

Buffer Cache中可以有很多块,再次查询A3_70M时,物理读大大减少。

而全表扫描A4_70M,只能反复使用辅LRU中的块,几乎无法占用主LRU中的块,因此在Buffer Cache中块数较少,每次物理读都很高。

步10:回答问题2

为什么连续两次查询A3_70M,就没有物理读了?可以连续两次全表扫描一下A3_70M,查看结果:

SQL> select lru_flag,count(*) from x$bh a,dba_objects b where a.obj=b.data_object_id and object_name='A3_70M' group by lru_flag;

LRU_FLAG   COUNT(*)

---------- ----------

6       1004

2       8254

0          1

一共9000多个块,8000多个在主LRU,1000多一点在辅助LRU。A3_70M表的全部块,都可以被缓存到Buffer Cache中。

当再次查询A4_70M时,A4_70M将又反复占用辅助LRU中的块,A3_70M留在辅助LRU中的1000多一点块会被覆盖,所以,当A3_70M、A4_70M交替查

询时,每次A3_70M在辅助LRU中的块都会被覆盖,因此,它会有少量物理读,但,当连续查询A3_70M时,辅助LRU中的块没被覆盖,就不会有物理读了。

好,问题已经解答了,让我们总结一下吧。

总结:

1、flush了buffer cache、或刚刚开启数据库时,所有的可用块都会链接到辅助LRU中。

2、查找可用块的过程,是先找辅助LRU,再从主LRU的冷端尾开始找。

3、全表扫描在辅助LRU找到块后,不会将块读进主LRU。所以,全表扫描的结果很容易被覆盖。

4、非全表扫描时,在辅助LRU找到块后,会将块移到主LRU的冷端头。这一点我们还没验证过。

5、全表扫描的块,如果再次以非全表扫描方式访问,TCH列会增加,但会一直留在辅助LRU,不会被移到主LRU冷端头。只有等到TCH值超过2时,才会在

下次被扫描到时,移到主LRU热端。

第4点和第5点,我们并没用测试验证,但找个这样的测试也是很简单的。留给大家自己验证一下吧,研究Internal,结果不是目的,过程更有

意义。

最后还有一个注意事项,这个测试只能在10G下做,因为11GR2后有些改变,即使是开库后第一次全表扫描,也不会把块移往主LRU,这样其实更合理,Oracle其实一直没有停止对内核优化步伐。

另外,本篇中除这个测试外,其他测试都可以在10G、11GR2下做。

lru oracle,一个测试理解什么是主、辅LRU(oracle cuug)相关推荐

  1. oracle ssh测试不通过,ssh 连接不上 oracle linux 7.2

    问题描述 oralce linux 可以ssh到其他设备,可是其他设备ssh不上oracle linux ssh username@hostip -v OpenSSH_6.6.1,OpenSSL 1. ...

  2. oracle stalestats_深入理解oracle优化器统计数据(Optimizer Statistics)

    理解oracle优化器统计数据 首先来介绍oracle数据库使用基于规则优化器(RBO)来决定如何执行一个sql语句.基于规则优化器顾名思义,它是遵循一组规则来判断一个sql语句的执行计划.这组规则是 ...

  3. oracle 压测工具 ld,ORACLE压力测试工具

    Swingbench for oracleRAC使用方法图解 1 Swingbench 简述 1.1 概述 这是Oracle UK的一个员工在一个被抛弃的项目的基础上开发的.目前稳定版本2.2,最新版 ...

  4. Oracle的概念理解

    1.了解一些关于数据库的概念 2.了解oracle背景 3.oracle数据库服务器的组成 4.oracle数据库服务器与orcl数据库的关系 5.如何在oracle数据库服务器中创建多个数据库 6. ...

  5. 用oracle怎么测试,oracle – 如何(单位)测试数据密集的PL / SQL应用程序

    有几种不同的PL / sql测试工具. Steven Feuerstein已经写了两个 utplsql和 Quest Code Tester for Oracle(以前的QUTE).我是utplsql ...

  6. 1.oracle的dump理解一 BH buffer header

    1.oracle的dump理解一 BH buffer header 欢迎转载,转载请标明出处:http://blog.csdn.net/notbaron/article/details/5122844 ...

  7. 论高危职业,测试员坦然垫底,揭秘一个测试员疯狂的全过程!

    1.你把时间浇灌在哪里,哪里就会开花结果. 大三在考研与工作的纠结中,我最终选择了工作,据学长学姐的推荐下就这样开始了我的测试学习之路.因为从未接触过,在图书馆借了几本书,越看越发现和学长学姐口中说的 ...

  8. 斯坦福大学马腾宇:无法理解现有的深度学习算法?那就设计一个能理解的

    2020-01-22 05:41:34 作者 | 丛末 编辑 | Camel 本科毕业于清华姚班.博士毕业于普林斯顿大学,师从 Sanjeev Arora 教授,马腾宇作为 AI 学界一颗冉冉升起的新 ...

  9. LinkedHashMap 的理解以及借助其实现LRU

    LinkedHashMap 的理解以及借助其实现LRU LinkedHashMap中有一个参数 accessOrder,这个参数定义了LinkedHashMap的访问顺序. LinkedHashMap ...

最新文章

  1. 快速原型工具 原型可视化
  2. Web3.0来了!玩法变了
  3. ABAP中创建动态内表的三种方法(转载)
  4. android打印intent flag,Android flag详解
  5. LeetCode数据库 176. 第二高的薪水
  6. VIRT,RES,SHR,虚拟内存和物理内存(转)
  7. 新零售讲堂之时代下的传统零售业,何去何从?
  8. 大数据治理体系如何搭建
  9. 运动控制系统课程设计
  10. SecureCRT for mac 破解安装
  11. UltraEdit 26 总是偶尔提示运行的是试用模式
  12. 清华OS前置知识:80386处理器
  13. 【数据结构】leetcode707:python实现链表设计;leetcode142:环形链表
  14. 缩放指数型线性单元(SELU)
  15. 九宫怎么排列和使用_奇门遁甲九宫数字 九宫数字的排列和算法
  16. 沧小海深入剖析xilinx的GTP/GTX核,掌握高速串行收发机制——第六章 接收端结构及功能说明
  17. 产品可用性原则:网页设计点睛秘笈
  18. 在移动硬盘里移动视频文件到移动硬盘 另外一个文件夹 显示正在计算_稳定可靠的数据之仓 柯达X200 SSD固态移动硬盘体验评测...
  19. golang与手机如何实现一些自动化操作?
  20. 我是如何从屌丝程序员逆袭成为大厂总监的?

热门文章

  1. ASDL用户端设备(无线猫)配置及各种设置综合
  2. error C2365: : redefinition:previous definition was
  3. [MacOSX]_[Mac Book电脑的快捷键*长期更新]
  4. 【Leetcode刷题记录_C++】【贪心】
  5. 5-7课:与二分查找共组双子星座:快速排序
  6. idm下载器2024官方最新中文版免费下载
  7. ubuntu 直接安装rails环境
  8. 【安卓逆向】CTF实战分析
  9. android fastboot命令大全,ADBFastboot常用命令
  10. Java在线音乐播放系统的设计与实现