Shared Pool 的转储与分析:
使用如下命令可以对共享池Library Cache信息进行转储分析:
ALTER SESSION SET EVENTS 'immediate trace name LIBRARY_CACHE level LL';
其中LL代表Level级别,对于9.2.0及以后版本,不同Level含义如下:
·Level=1,转储Library Cache统计信息;
·Level=2,转储Hash Table概要;
·Level=4,转储Library Cache对象,只包含基本信息;
·Level=8,转储Library Cache对象,包含详细信息(如:child references、pin waiters等);
·Level=16,增加heap sizes信息;
·Level=32,增加heap信息。
Library Cache由一个Hash表组成,而Hash表是一个由Hash Buckets组成的数组,每个Hash Bucket都包含Library Cache Handle的一个双向链表。Library Cache Handle指向Library Cache Object和一个引用列表。Library Cache对象进一步分为依赖表、子表和授权表等。
通过以下命令对Library Cache进行转储:
alter session set events 'immediate trace name LIBRARY_CACHE level 4';
接下来进一步讨论一下Shared Pool的内容存储。先进行相应的查询,获得测试数据:
sys@NEI> conn tq/tq
Connected.
tq@NEI> create table emp as select * from scott.emp;
Table created.
tq@NEI> conn / as sysdba
Connected.
tq@NEI> startup force
sys@NEI> conn scott/tiger
Connected.
scott@NEI> select * from emp;
scott@NEI> conn tq/tq
Connected.
tq@NEI> select * from emp;tq@NEI> col sql_text for a30
tq@NEI> select sql_text,version_count,hash_value,to_char(hash_value,'xxxxxxxxxx') HEX,address
2 from v$sqlarea where sql_text like 'select * from emp%';
SQL_TEXT VERSION_COUNT HASH_VALUE HEX ADDRESS
------------------------------ ------------- ---------- ----------- --------
select * from emp 2 1745700775 680d47a7 43A673D0tq@NEI> select sql_text,username,address,hash_value,to_char(hash_value,'xxxxxxxxxx') HEX_HASH_VALUE,
2 child_number,child_latch
3 from v$sql a,dba_users b
4 where a.parsing_user_id=b.user_id and sql_text like 'select * from emp%';
SQL_TEXT USERNAME ADDRESS HASH_VALUE HEX_HASH_VA CHILD_NUMBER CHILD_LATCH
------------------------------ ---------- -------- ---------- ----------- ------------ -----------
select * from emp TQ 43A673D0 1745700775 680d47a7 1 1
select * from emp SCOTT 43A673D0 1745700775 680d47a7 0 1
这里可以看出v$sqlarea和v$sql两个视图的不同之处,v$sql中为每一条SQL保留一个条目,而v$sqlarea中根据sql_text进行group by,通过version_count计算子指针的个数。
在以上两次查询中,两条SQL语句因为其代码完全相同,所以其ADDRESS、HASH_VALUE也完全相同。这就意味着,这两条语句在共享池中的存储位置是相同的(尽管其执行计划可能不同),代码得以共享。在SQL解析过程中,Oracle将SQL文本转换为相应的ASCII数值,然后根据数值通过Hash函数计算其HASH_VALUE,再通过HASH_VALUE在Shared Pool中寻找是否存在相同的SQL语句,如果存在则进入下一步骤;如果不存在则尝试获取Shared Pool Latch,请求内存,存储该SQL代码。
在这里有一个问题需要说明一下,因为大小写字母ASCII值是不同的,所以Oracle会把大小写不同的代码作为不同的SQL来处理。看一下测试:
tq@NEI> select * from scott.dept;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTONtq@NEI> select * from scott.DEPT;
DEPTNO DNAME LOC
---------- -------------- -------------
10 ACCOUNTING NEW YORK
20 RESEARCH DALLAS
30 SALES CHICAGO
40 OPERATIONS BOSTONtq@NEI> select sql_text,hash_value from v$sql where sql_text like 'select * from scott%';
SQL_TEXT HASH_VALUE
------------------------------ ----------
select * from scott.DEPT 3411718958
select * from scott.dept 911793802
注意到以上的输出,仅仅是大小写的不同使得原本相同的SQL语句变成了两条“不同的代码”,所以从这里可以看出,SQL的规范编写非常重要。
SQL解析首先要进行的是语法解析,语法无误后进行下一个步骤,进行语义分析,在此步骤中,Oracle需要验证对象是否存在、相关用户是否具有权限、引用的是否是相同的对象。
对于先前的查询,实际上emp表来自不同的用户,那么SQL的执行计划也就不同了(当然影响SQL执行计划的因素还有很多,包括优化器模式等),通过对象依赖关系可以看到这个不同:
tq@NEI> col SQL_TEXT for a30
tq@NEI> col TO_OWNER for a10
tq@NEI> col TO_NAME for a10
tq@NEI> select a.*,to_char(to_hash,'xxxxxxxxxx') Hex_HASH_VALUE
2 from v$object_dependency a where to_name='EMP';
FROM_ADD FROM_HASH TO_OWNER TO_NAME TO_ADDRE TO_HASH TO_TYPE HEX_HASH_VA
-------- ---------- ---------- ---------- -------- ---------- ---------- -----------
43A5FD00 3494121331 TQ EMP 43A604F8 127687888 2 79c5cd0
43A673D0 1745700775 SCOTT EMP 43A67194 3371416969 2 c8f3bd89
回忆一下前面介绍过的Buffer Cache的管理,其中Bucket→BH(buffer header)→Buffer的管理方式与以上Library Cache的管理原理完全类似。
Library Cache Handle可以被看作库缓存对象的概要信息,Handle上存有指针指向Library Cache Object,Handle中还包含对象名、namespace、时间戳、引用列表、锁定对象及pin对象列表等信息。这里还需要说明的是Handle上的指针指向的是Library Cache Object的Heap 0,库缓存对象可能占用多个内存Heap,Heap 0则记录了控制信息,包括对象类型、对象依赖表、指向其他Heap的指针等。
至于Dictionary Cache信息则可以通过如下命令进行转储:
ALTER SESSION SET EVENTS 'immediate trace name row_cache level N';
这里的N可以取的值如下:
·1,转储dictionary cache的统计信息;
·2,转储hash表的汇总信息;
·8,转储dictionary cache中的对象的结构信息。
- The End -