Oracle Library Cache深入解析
每一个进入库缓存的对象,在库缓存中都被按照本身内容分割成多块进行存贮。Oracle这样做的目的是为了更灵活的内存管理,因为在内存寻找大块连续的内存,总比寻找小块连续内存更慢一些.如果一个库缓存对象(如一条SQL语句的执行计划),它所占的内存被切割成4个小块,它们分别被存放在库缓存的各处,并且互不相连。为了将这4个小块组合起来,Oracle另外这个库缓存对象分配一小块内存,这块内存中存有其他4个小块内存的地址,并且,还有一些有关此库缓存对象的基本信息,如名字、类型等等,这块内存就叫库缓存对象句柄(handles)。
Library Cache结构示意图如下:
在访问库缓存对象时,比如软解析时,要从库缓存中读取执行计划。Oracle首先找到句柄,读取句柄中的信息,这就叫做一次库缓存Get。如果库缓存中不包括对象的句柄信息,Oracle就要重新在库缓存中分配内存、构造句柄,这就是库缓存句柄未命中(Get Miss)。相反,如果在库缓存中找到了对象句柄,就是库缓存句柄命中(Get Hit)。硬解析时,就会发生Get Miss。而软解析则是Get Hit。
--------------------------------------------------------------------------------
Linux-6-64下安装Oracle 12C笔记
在CentOS 6.4下安装Oracle 11gR2(x64)
Oracle 11gR2 在VMWare虚拟机中安装步骤
Debian 下 安装 Oracle 11g XE R2
--------------------------------------------------------------------------------
在取出句柄中的其他内存块地址后,每访问一个内存块,都叫做一次库缓存Pin。如果相应的内存块已经不在内存中了,这就是Pin Miss,Pin的未命中。相反就是Pin Hit。
当库缓存中对象发生改变后,会引起其他一些对象的无效(Invalidation)。比如,你修改了一个表的结构,那么,选择了这个表的SQL语句的执行计划就会变的无效。其实大部分对表的DDL操作,都会造成相关SQL语句执行计划的无效。就连Grant(授权)、Revoke(撤消权限)这样看来跟执行计划耗无关系的操作,都会引起无效。如果有一个表TAB1,你发布了“Grant 某权限 on tab1 to 某用户”,或“revoke 某权限 on tabl from 某用户”这样的操作,那么,所有和TAB1表有关的执行计划都将无效。无效之后,库缓存对象除句柄外的所有内存块,都将被清除。再使用到对象后,必须重新加载对象。如上例,如果你对TAB1使用了DDL语句,那么所有使用了TAB1表语句的执行计划都将无效,你再使用这些语句时,就必须重新硬解析语句。
案例:
16:54:51 SCOTT@ prod>select * from dept1;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
Elapsed: 00:00:00.06
16:54:03 SYS@ prod> select NAMESPACE,GETS,PINS,RELOADS,INVALIDATIONS from v$librarycache
NAMESPACE GETS PINS RELOADS INVALIDATIONS
------------------------------ ---------- ---------- ---------- -------------
SQL AREA 7722 30134 30 97
TABLE/PROCEDURE 10906 8328 88 0
BODY 608 801 0 0
TRIGGER 24 41 0 0
INDEX 96 62 0 0
CLUSTER 485 300 0 0
QUEUE 36 168 0 0
APP CONTEXT 14 14 0 0
RULESET 3 3 0 0
SUBSCRIPTION 5 5 0 0
EDITION 58 99 0 0
DBLINK 5 0 0 0
OBJECT ID 59 0 0 0
SCHEMA 3584 0 0 0
DBINSTANCE 1 0 0 0
15 rows selected.
Elapsed: 00:00:00.01
在访问对象dept1上,做DDL操作,导致原来的执行计划变得无效
16:55:01 SCOTT@ prod>grant all on dept1 to hr;
Grant succeeded.
Elapsed: 00:00:00.26
16:55:24 SCOTT@ prod>select * from dept1;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTON
Elapsed: 00:00:00.04
16:55:29 SCOTT@ prod>
16:55:08 SYS@ prod>r
1* select NAMESPACE,GETS,PINS,RELOADS,INVALIDATIONS from v$librarycache
NAMESPACE GETS PINS RELOADS INVALIDATIONS
------------------------------ ---------- ---------- ---------- -------------
SQL AREA 7781 30422 32 100
TABLE/PROCEDURE 10980 8420 88 0
BODY 623 817 0 0
TRIGGER 26 43 0 0
INDEX 96 62 0 0
CLUSTER 488 302 0 0
QUEUE 36 168 0 0
APP CONTEXT 14 14 0 0
RULESET 3 3 0 0
SUBSCRIPTION 5 5 0 0
EDITION 59 101 0 0
DBLINK 5 0 0 0
OBJECT ID 59 0 0 0
SCHEMA 3595 0 0 0
DBINSTANCE 1 0 0 0
15 rows selected.
Elapsed: 00:00:00.03
16:55:34 SYS@ prod>
因此,使用DDL语句是需要注意的,如果没有要求立即使用DDL,我们最好等到数据库并不繁忙的时刻,再执行DDL。作为DBA,这一点一定要牢记,除非要求立即执行,否则等到数据库并不繁忙时再执行任何DDL。
再补充一点,无效和库缓存对象的老化并不一样。老化是连句柄带对象的所有内存块都被清除出去了。而无效是只在库缓存中保留对象句柄,但所有其他内存块都被清除出去。对于无效的对象,当再次重新调用到它时,Oracle会再次将它调入到库缓存中,这个操作被称为Reload。一般说来,Reload与Get是无关的,因为Reload是在对象无效后才发生的,而对象的无效并不影响对象句柄。好,说了这么多,下面我们来看这些值的意义。
我们已经讲述了Get、Pin与它们的命中、未命中,还有什么是Invalidation和Reload。在OLTP系统中,Get的命中率应该在90%之上。而Reload和Pin的次数的比值,应该小于1%。如果超出了这些数值范围,就说明库缓存的使用有问题。问题的原因主要有两个,没有使用绑定变量或是库缓存太小。不过Reload和Pin的比例过高,也可能是在繁忙时执行了DDL所导致的。
另外,V$librarycache的第一列是NAMESPACE,也就是名称空间。它相当于存储在库缓存中对象的类型。具体的名称空间是什么意思呢?就是对象的名字所在的范围,比如表和列的名字就不在一个范围内。也就是说表名和列名可以重复,还有用户名和表、列也不在同一范围内,用户名也可以和表、列名相同。我可以有个叫做AA的表,也可以有叫做AA的用户。这两个AA处在不同的范围内,也就明它们的名称空间不同。这就好像在北京有个电话号码是12345678,在上海也有个12345678,这两个电话号码虽然相同,但不会引起问题,因为它们在不同的范围内。这个范围,也可以说是类型。
我显示一下V$librarycache的所有行(列只有一部分):
SQL> select * from v$librarycache;
NAMESPACE GETS GETHITS GETHITRATIO PINS PINHITS
--------------- ---------- --------------------- ---------- ----------
SQL AREA 21811 4149 .190225116 120258 105272
TABLE/PROCEDURE 25152 16372 .650922392 60649 46008
BODY 4360 4098 .939908257 5931 5537
TRIGGER 320 251 .784375 1655 1576
INDEX 453 128 .282560706 2065 1531
CLUSTER 755 728 .964238411 2339 2296
OBJECT 0 0 1 0 0
PIPE 0 0 1 0 0
JAVA SOURCE 0 0 1 0 0
JAVA RESOURCE 0 0 1 0 0
JAVA DATA 0 0 1 0 0
可以看在库缓存中共有11个名称空间,我们基本上可以说库缓存中有11种类型的信息。有一个非常重要的指标,就是库缓存命中率,这个命中率就是库缓存中所有对象的GETHITRAIO,它的计算方法如下:
select 1-sum(gethits)/sum(gets) fromv$librarycache;
这个比率应该在90%以上。
还有一个比率也很重要,就是Reload和Pin的比值,这个比值应该小于1%。
如果没有达到这些比例,解决方法很简单,问题或者是SQL语句没有共享,或者是共享池太小。
有关库缓存命中率,也可以查看STATSPACK报告中的Library Hit %项。这个我们上面已经说过了。
更多详情见请继续阅读下一页的精彩内容: