Library cache结构
Library cache最主要的功能就是存放用户提交的SQL语句,SQL语句相关的解析树(解析树也就是对SQL语句中所涉及到的所有对象的展现)--->共享SQL区(shared SQL areas),私有SQL区(private SQLareas,如果配置了共享服务器),执行计划,用户提交的PL/SQL程序块(包括匿名程序块,存储过程,包,函数等)以及它们转换后能够被Oracle执行的代码等,为了对这些内存结构进行管理,library cache中还存放了很多控制结构,包括lock,pin,dependency table,11G中的mutex等。
Library cache需要解决三个问题:
(1).快速定位的问题:Library cache中对象众多,Oracle如何管理这些对象,以便服务进程可以迅速找到他们需要的信息。比如某个服务进程需要迅速定位某个SQL是否存在于Librarycache中。-
--Oracle利用hash table结构来解决library cache中快速定位的问题
(2).关系依赖的问题:Library cache中的对象存在复杂的依赖关系,当某个objec失效时,可以迅速将依赖其的对象也置为失效状态。比如某个表发生了结构变化,依赖其的SQL语句需要重新解析。---LCO中
dependency table
(3).并发控制的问题:Library cache中必须有一个并发控制的机构,比如锁机制,来管理大量共享对象的并发访问和修改的问题,比如某个SQL在重新编译的同时,其所依赖的对象不能被修改。----LATCH LOCK PIN
Library cache由一个hash表组成,hash表是由hash buckets组成的数组。
每个hash bucket都是包含library cache handle的一个双向链表。
library cache handle指向library cache object和一个引用列表。
library cache 对象进一步分为:依赖表、子表、授权表等
同一个SQL语句,HASH值相同,放在同一个library cache handle--如绑定变量,是用同一个library cache handle下不同的的子游标。不同的SQL语句,HASH值相同放在同一hash bucket的不同library cache handle。
Hash 算法
Oracle在内部管理中大量的使用到了hash,使用hash的目的就是为了快速查找和定位.
对数值进行hash运算,产生一个索引号,然后根据索引号将数值放置到相应的hash bucket中去.
根据hash运算的法则,会产生多个索引号,每一个索引号对应一个hash bucket(一个数值列).
在寻找数值的时候,将搜寻的数值进行hash,产生一个索引号,那么这个数值一定在这个索引号对应的 hash bucket中,于是直接跳转到这个hash bucket中进行遍历。这样在定位数据的时候,就能够大大的减少遍历的数量。
hash bucket:库缓存中就是使用hash bucket来管理的
1、首先根据shared_pool_size指定的尺寸来自动计算hash bucket的个数
2、每个hash bucket后面都串联着多个句柄
句柄描述了library cache里面的对象的一些属性,包括名称、标记、指向对象所处的内存地址的指针
library cache handle:-----OBJECT Handle
一个handle管理着一个library cache object,handle对LCO起到指针作用。
Library cache中所有对象的访问是通过利用library cache handle来实现的
当一个进程请求library cache object, librarycache manager就会应用一个hash 算法,从而得到一个hash 值,根据相应的hash值到相应的hash bucket中去寻找。
如果library cache object在内存中,那么这个library cache handle就会被找到。有时候,当shared pool不够大,library cache handle会保留在内存中,然而library cache heap由于内存不足被age out,这个时候我们请求的object heap就会被重载。最坏的情况下,library cache handle在内存中没有找到,这个时候就必须分配一个新的library cachehandle,同时object heap也会被加载到内存中。
###############
library cache object的结构: --LCO
见上图,主要保存SQL的实际信息,包括:
dependency table --当前LCO依赖的其它LCO信息,如SQL语句依赖的表、视图等。
1.Chile table----保存当前LCO的子LCO信息
一个LCO会有多个子LCO---多版本问题。---一条SQL至少有一个parent cursor 和 child cursor。
存在不同版本SQL可能是:不同用户执行相同SQL文件的SQL.--也可能是BUG。
SQL语句文本一样-HASH值一样,执行计划不一样的情况有:--多版本
1.不同用户下有同名的表,不同的用户执行查询此表操作,就会出现不同执行计划。
2.绑定变量时,如果绑定变量的字符串(
详见:绑定变量分级)变化达到一定程度,执行计划也会不一样
HIGH VERSION高版本的SQL语句有多个子LCO,每个子HANDLE对应一个子LCO。---parent cursor 里对应的所有child cursor的指针都会保存在child table里面。-
-parent cursor和child cursor都是用library cache object handle 存储在Library Cache里的。---结构一样
当子LCO数量很多--SQL版本数(VERSION COUNT)很高,会话扫描BUCKET时间变长,持有latch:library cache时间也变长,定位到具体的child sql cursor时间相应变长(顺序扫描HANDLE),latch:library cache争用的概念增加。
查看SQL版本信息:
BYS@ bys3>select * from (select version_count,sql_id,sql_text from v$sqlarea order by version_count desc) where rownum<5 ;
BYS@ bys3>select version_count,sql_id,sql_text from v$sqlarea where sql_text like 'select * from bys.dept';
VERSION_COUNT SQL_ID SQL_TEXT
------------- ------------- ------------------------------
1 f4yk5kundsxfd select * from bys.dept
2.data blocks ---保存SQL语句、执行计划、执行文本等信息。
ORACLE通过地址指向存储 这些信息的HEAP /CHUNK。HEAP 6存储着SQL执行计划。
ORACLE 10.2.0.4开始可以通过dbms_shared_pool.purge 包清理HEAP 6中执行计划。
3.dependency table
指向本对象所依赖的对象,比如:select * from emp这个cursor的对象,依赖emp这个表,这里指向了emp这个表的handle。
####################################################3
通过x$kglob找出SQL语句父游标地址,并DUMP library cache,在TRACE文件中父游标的地址中找到SQL语句。
会话1
SYS@ bys3>select * from bys.dept;
SYS@ bys3>col KGLNAOBJ for a40
SYS@ bys3>
select kglhdadr,kglhdpar,kglnaobj,kglobhd0 from x$kglob where kglnaobj like 'select * from bys.dept%';
KGLHDADR KGLHDPAR KGLNAOBJ KGLOBHD0
-------- -------- ------------------------------ --------
23ACB574 248344B8 select * from bys.dept 242B7D1C --23ACB574子游标地址
248344B8 248344B8 select * from bys.dept 23FE4684 --248344B8父游标地址,父游标heap 0地址-其实是描述符-23FE4684
select KGLHDADR,KGLHDPAR,KGLNAOBJ,KGLOBHD0 from x$kglob where kglnaobj like 'select * from bys.dept%' and KGLHDADR<>KGLHDPAR ; 查出子游标
select KGLHDADR,KGLHDPAR,KGLNAOBJ,KGLOBHD0 from x$kglob where kglnaobj like 'select * from bys.dept%' and KGLHDADR=KGLHDPAR ; 查出父游标
SYS@ bys3>
select KSMCHPTR,KSMCHCOM,KSMCHCLS,KSMCHSIZ from x$ksmsp where KSMCHPAR='23FE4684'; --通过上一步查出的 heap 0描述符找到查看父游标所在CHUNK地址大小描述状态
KSMCHPTR KSMCHCOM KSMCHCLS KSMCHSIZ
-------- ---------------- -------- ----------
241D3A44 KGLH0^a8dc75cd recr 4096
新打开一个会话:DUMP library cache并查找SQL语句。
SYS@ bys3>alter session set events 'immediate trace name heapdump level 2050';
SYS@ bys3>select value from v$diag_info where name like 'De%';
VALUE
----------------------------------------------------------------------------------------------------
/u01/diag/rdbms/bys3/bys3/trace/bys3_ora_31638.trc
#################
VI中查询: 在241D3A44这个地址开始的这个 Chunk中找到了SQL语句
Chunk 241d3a44 sz= 4096 recreate "KGLH0^a8dc75cd " latch=(nil)
ds 23fe4684 sz= 4096 ct= 1
Dump of memory from 0x241D3A44 to 0x241D4A44
241D3A40 80001001 241D2A44 00000000 [....D*.$....]
241D3A50 00000000 00000000 00000000 000A0FFF [................]
………………
Chunk 2405e530 sz= 4096 recreate "SQLA^bf04295e " latch=(nil)
Dump of memory from 0x2405E530 to 0x2405F530
2405E530 80001001 2405E164 2526A6EC 237A8414 [....d..$..&%..z#]
………………
2405E680 00000000 00000000 00000000 00000000 [................]
2405E690 00000000 00000000 F4A4D8E8 735DAFAF [..............]s]
2405E6A0 00000000 00000049 2405E65C 11390064 [....I...\..$d.9.]
2405E6B0 01748F8F 18150001 407EC500 0A8A0500 [..t.......~@....]
2405E6C0 00020103 00090203 093A0000 1E070604 [..........:.....]
2405E6D0 F0836A0A A8E0F183 E036E426 83E426A8 [.j......&.6..&..]
2405E6E0 03F383F5 02030302 008E0000 00000025 [............%...]
2405E6F0 2405E6A4 110B3B04 656C6573 2A207463 [...$.;..select *]
2405E700 6F726620 7962206D 65642E73 00257470 [ from bys.dept%.]
2405E710 0000003D 2405E6EC 110B3B34 0000000D [=......$4;......]
2405E720 00000801 00170040 00010369 00000018 [[email protected].......]
…………
###########################################################################
通过x$kglob找出SQL语句子游标地址及堆6地址,并DUMP library cache,在TRACE文件中查看的内容。
堆0 heap 0 --属于父游标-library cache handle,子游标里也有两个堆,堆0 存放指向堆6的地址
SYS@ bys3>select * from bys.dept;
SYS@ bys3>col KGLNAOBJ for a25
SYS@ bys3>
select kglhdadr,kglhdpar,kglnaobj,KGLOBHS0,kglobhd0,KGLOBHS6,KGLOBHD6 from x$kglob where kglnaobj like 'select * from bys.dept%';
KGLHDADR KGLHDPAR KGLNAOBJ KGLOBHS0 KGLOBHD0 KGLOBHS6 KGLOBHD6
-------- -------- ------------------------- ---------- -------- ---------- --------
2358B76C 23D0705C select * from bys.dept 4348 2526A068 4060 243F2238
23D0705C 23D0705C select * from bys.dept 4516 23D65B44 0 00
父游标LibraryHandle 地址KGLHDPAR:23D0705C 子游标LibraryHandle地址KGLHDADR:2358B76C,
父游标堆0描述KGLOBHD0:23D65B44,子游标堆0描述:2526A068,子游标堆6描述KGLOBHD6:243F2238
这一点可以DUMP查看, alter session set events 'immediate trace name heapdump_addr level 2,addr0x23b31e80‘; 类似以下:desc=0x23b31e80这种就可以与上面查出的KGLOBHD0字段信息对应--我这是后来增加的,没法对应上了。
******************************************************
HEAP DUMP heap name="KGLH0^1020848" desc=0x23b31e80
extent sz=0xff4 alt=32767 het=28 rec=9 flg=2 opc=0
parent=0x200010b4 owner=0x23b31e4c nex=(nil) xsz=0xfe4 heap=(nil)
fl2=0x26, nex=(nil), dsxvers=1, dsxflg=0x0
dsx first ext=0x240b19c4
EXTENT 0 addr=0x240b19c4
Chunk 240b19cc sz= 44 p
SYS@ bys3>select KSMCHPTR,KSMCHCOM,KSMCHCLS ,KSMCHSIZ from x$ksmsp where KSMCHPAR='23D65B44';
--通过上一步查出的父游标heap 0描述符找到查看父游标所在CHUNK地址大小描述状态
KSMCHPTR KSMCHCOM KSMCHCLS KSMCHSIZ
-------- ---------------- -------- ----------
243F1D68 KGLH0^a8dc75cd recr 4096
SYS@ bys3>select KSMCHPTR,KSMCHCOM,KSMCHCLS ,KSMCHSIZ from x$ksmsp where KSMCHPAR='2526A068';
--通过上一步查出的子游标heap 0描述符找到查看子游标堆0所在CHUNK地址大小描述状态:
KSMCHPTR KSMCHCOM KSMCHCLS KSMCHSIZ
-------- ---------------- -------- ----------
23FDD830 KGLH0^a8dc75cd recr 4096 --KGLH0^a8dc75cd --H0 heap 0
SYS@ bys3>select KSMCHPTR,KSMCHCOM,KSMCHCLS ,KSMCHSIZ from x$ksmsp where KSMCHPAR='243F2238';
--通过上一步查出的子游标heap 6描述符,找到查看子游标堆6所在CHUNK地址大小描述状态
KSMCHPTR KSMCHCOM KSMCHCLS KSMCHSIZ
-------- ---------------- -------- ----------
23FDB830 SQLA^a8dc75cd recr 4096 --SQLA^a8dc75cd -SQL area
SYS@ bys3>col sql_text for a25
SYS@ bys3>select sql_id,hash_value,address,child_address,sql_text from v$sql where sql_text like 'select * from bys.dept%';
--查看SQL语句的SQL_ID,HASH_VALUE ADDRESS CHILD_AD等信息,与下面DUMP的信息对照。
SQL_ID HASH_VALUE ADDRESS CHILD_AD SQL_TEXT
------------- ---------- -------- -------- -------------------------
f4yk5kundsxfd 2833020365 23D0705C 2358B76C select * from bys.dept
新会话DUMP
SYS@ bys3>alter session set events 'immediate trace name library_cache level 16';
Session altered.
level 1,转储library cache统计信息;level 2,转储hash table 概要
level 4,转储library cache对象基本信息;level 4,转储library cache对象详细信息
level 16,增加了heap sizes信息。
SYS@ bys3>select value from v$diag_info where name like 'De%';
VALUE
---------------------------------------------------
/u01/diag/rdbms/bys3/bys3/trace/bys3_ora_22403.trc
#########################################
Bucket: #=30157 Mutex=0x26ab5658(2e0000, 78, 0, 6)
LibraryHandle: Address=0x23d0705c Hash=a8dc75cd LockMode=0 PinMode=0 LoadLockMode=0 Status=VALD
##Address=0x23d0705c与x$kglob.KGLHDPAR父游标地址相符.Hash=a8dc75cd与x$ksmsp.KSMCHCOM相符,转换为10进制则与v$sql.HASH_VALUE相符;
ObjectName: Name=select * from bys.dept ##执行的语句内容,与x$kglob.KGLNAOBJ
FullHashValue=2cd147d1d9b8972be27a4596a8dc75cd Namespace=SQL AREA(00) Type=CURSOR(00) Identifier=2833020365 OwnerIdn=0
##Identifier=2833020365与v$sql.HASH_VALUE相符,Namespace=SQL AREA(00) SQL区域
Statistics: InvalidationCount=0 ExecutionCount=1 LoadCount=2 ActiveLocks=0 TotalLockCount=1 TotalPinCount=1
Counters: BrokenCount=1 RevocablePointer=1 KeepDependency=1 Version=0 BucketInUse=0 HandleInUse=0 HandleReferenceCount=0
Concurrency: DependencyMutex=0x23d070c4(0, 1, 0, 0) Mutex=0x23d07120(46, 39, 0, 6)
Flags=RON/PIN/TIM/PN0/DBN/[10012841]
WaitersLists:
Lock=0x23d070b4[0x23d070b4,0x23d070b4]
Pin=0x23d070a4[0x23d070a4,0x23d070a4]
LoadLock=0x23d070e8[0x23d070e8,0x23d070e8]
Timestamp: Current=01-04-2014 18:03:50 ##时间戳
HandleReference: Address=0x23d0718c Handle=(nil) Flags=[00]
ReferenceList:
Reference: Address=0x23fdcb14 Handle=0x2345e2a8 Flags=ROD[21]
LibraryObject: Address=0x243f1dc8 HeapMask=0000-0001-0001-0000 Flags=EXS[0000] Flags2=[0000] PublicFlags=[0000]
DataBlocks:
Block: #='0' name=KGLH0^a8dc75cd pins=0 Change=NONE
Heap=0x23d65b44 Pointer=0x243f1e1c Extent=0x243f1d84 Flags=I/-/P/A/-/-
FreedLocation=0 Alloc=1.546875 Size=3.988281 LoadTime=4405191980
ChildTable: size='16'
Child: id='0' Table=0x243f2d18 Reference=0x243f2390 Handle=0x2358b76c ##子指针
Children:
Child: childNum='0'
L
ibraryHandle: Address=0x2358b76c Hash=0 LockMode=0 PinMode=0 LoadLockMode=0 Status=VALD
##子游标LibraryHandle地址Address=0x2358b76c,与x$kglob.KGLHDADR子游标地址相符
Name: Namespace=SQL AREA(00) Type=CURSOR(00)
Statistics: InvalidationCount=0 ExecutionCount=1 LoadCount=1 ActiveLocks=0 TotalLockCount=1 TotalPinCount=2
Counters: BrokenCount=1 RevocablePointer=1 KeepDependency=0 Version=0 BucketInUse=0 HandleInUse=0 HandleReferenceCount=0
Concurrency: DependencyMutex=0x2358b7d4(0, 0, 0, 0) Mutex=0x23d07120(46, 39, 0, 6)
Flags=RON/PIN/PN0/EXP/CHD/[10012111]
WaitersLists:
Lock=0x2358b7c4[0x2358b7c4,0x2358b7c4]
Pin=0x2358b7b4[0x2358b7b4,0x2358b7b4]
LoadLock=0x2358b7f8[0x2358b7f8,0x2358b7f8]
ReferenceList:
Reference: Address=0x243f2390 Handle=0x23d0705c Flags=CHL[02]
LibraryObject: Address=0x23fdd890 HeapMask=0000-0001-0001-0000 Flags=EXS[0000] Flags2=[0000] PublicFlags=[0000]
Dependencies: count='1' size='16' table='0x23fde7a4'
Dependency: num='0'
Reference=0x23fddcb0 Position=18 Flags=DEP[0001]
Handle=0x2433a460 Type=TABLE(02) Parent=BYS.DEPT
ReadOnlyDependencies: count='1' size='16'
ReadDependency: num='0' Table=0x23fde7f0 Reference=0x23fddc1c Handle=0x2345e2a8 Flags=DEP/ROD/KPP[61]
Accesses: count='1' size='16'
Dependency: num='0' Type=0009
DataBlocks:
Block: #='0' name=KGLH0^a8dc75cd pins=0 Change=NONE
Heap=0x2526a068 Pointer=0x23fdd8e4 Extent=0x23fdd84c Flags=I/-/-/A/-/-
#####Heap=0x2526a068子游标堆0的地址,与x$kglob.KGLOBHD0相符
FreedLocation=0 Alloc=1.382812 Size=3.964844 LoadTime=4405191980
Block: #='6' name=SQLA^a8dc75cd pins=0 Change=NONE
Heap=0x243f2238 Pointer=0x23fdc624 Extent=0x23fdb84c Flags=I/-/-/A/-/E
##Heap=0x243f2238这个就是子游标堆6的地址,与x$kglob.KGLOBHD6相符
FreedLocation=0 Alloc=3.785156 Size=3.964844 LoadTime=0
NamespaceDump:
--子游标信息
Child Cursor: Heap0=0x23fdd8e4 Heap6=0x23fdc624 Heap0 Load Time=01-04-2014 18:03:50 Heap6 Load Time=01-04-2014 18:03:50
NamespaceDump:
Parent Cursor: sql_id=f4yk5kundsxfd parent=0x243f1e1c maxchild=1 plk=n ppn=n
##父游标,sql_id=f4yk5kundsxfd与v$sql.sql_id相符,
###############################################
DUMP SQL语句父子游标的堆0和堆6
SYS@ bys3>select kglhdadr,kglhdpar,kglnaobj,KGLOBHS0,kglobhd0,KGLOBHS6,KGLOBHD6 from x$kglob where kglnaobj like 'select * from bys.test%';
KGLHDADR KGLHDPAR KGLNAOBJ KGLOBHS0 KGLOBHD0 KGLOBHS6 KGLOBHD6
-------- -------- ------------------------- ---------- -------- ---------- --------
240EDA68 239948A4 select * from bys.test 4348 23B31E80 4060 245908B0
239948A4 239948A4 select * from bys.test 4500 241368BC 0 00
alter session set events 'immediate trace name heapdump_addr level 2,addr 0x241368BC'; --使用这样的语句把父子游标的堆0、堆6全DUMP出来。
我把三个DUMP文件的开头贴一下:
父游标堆0:desc=字段与x$kglob.KGLOBHD0对应,heap name="KGLH0^ 堆名字也表明是堆0
******************************************************
HEAP DUMP heap name="KGLH0^1020848" desc=0x241368bc
extent sz=0xff4 alt=32767 het=28 rec=9 flg=2 opc=0
parent=0x200010b4 owner=0x24136888 nex=(nil) xsz=0xfe4 heap=(nil)
fl2=0x26, nex=(nil), dsxvers=1, dsxflg=0x0
dsx first ext=0x245903fc
EXTENT 0 addr=0x245903fc
Chunk 24590404 sz= 44 perm "perm " alo=44
Dump of memory from 0x24590404 to 0x24590430
子游标堆0:--我的版本是11.2.0.4,有的版本DUMP出来的heap name="CCURSE,,比较直观说明是子游标。。这 里只能通过desc=字段与x$kglob.KGLOBHD6对应
******************************************************
HEAP DUMP heap name="KGLH0^1020848" desc=0x23b31e80
extent sz=0xff4 alt=32767 het=28 rec=9 flg=2 opc=0
parent=0x200010b4 owner=0x23b31e4c nex=(nil) xsz=0xfe4 heap=(nil)
fl2=0x26, nex=(nil), dsxvers=1, dsxflg=0x0
dsx first ext=0x240b19c4
EXTENT 0 addr=0x240b19c4
Chunk 240b19cc sz= 44 perm "perm " alo=44
子游标堆6: --从DUMP名字也可以看出是存放SQL执行计划等的SQL区域。--有的版本DUMP出来这里显示的heapname="SQL AREA,我这个11.2.0.4版本上看就这样了。。
******************************************************
HEAP DUMP heap name="SQLA^1020848" desc=0x245908b0
extent sz=0xff4 alt=32767 het=184 rec=0 flg=2 opc=2
parent=0x200010b4 owner=0x245907e4 nex=(nil) xsz=0xfe4 heap=(nil)
fl2=0x27, nex=(nil), dsxvers=1, dsxflg=0x0
dsx first ext=0x24b12c54
EXTENT 0 addr=0x24b12c54
Chunk 24b12c5c sz= 44 perm "perm " alo=44