时间:2021-07-01 10:21:17 帮助过:30人阅读
关于cursor是oracle中开发人员经常使用的,这里我们不提开发人员所提的cursor,而是简单提下shared pool中的parent cursor和child cursor以及pga中的session cursor,以及硬解析、软解析、library cache的内部结构 shared pool中的library cache结构: libra
关于cursor是oracle中开发人员经常使用的,这里我们不提开发人员所提的cursor,而是简单提下shared pool中的parent cursor和child cursor以及pga中的session cursor,以及硬解析、软解析、library cache的内部结构
实际上,library cache object handle是以hash table的方式存储在library cache中,每一个hash bucket都对应不同的hash value,对于单个hash bucket而言,里面存储的就是哈希值相同的所有library cache object handle,同一个hash bucket中不同的library cache object handle之间会用指针连接起来,即同一个hash bucket中不同的library cache object handle组成该hash bucket中涉及的library cache object的库缓存对象句柄链表(library cache object handles)。
查看上面软解析和硬解析的过程,我们发现硬解析会较长时间的持有library cache latch,也会持有shared pool latch,虽然软解析也会持有library cache latch,但是持有次数相比硬解析要少,持有时间也会硬解析短,软解析不会持有shared pool latch;如果系统出现大量的硬解析,则会引起library cache latch和shared pool latch的争用,一般在OLTP系统中,经常在书中看见要我们更多的使用绑定变量来提高系统的性能的原因,在oracle 11g后,oracle用mutex替换了相关的library cache latch,mutex的作用除了有latch的作用,还有library cache pin的作用。
属性“Name”:表示的时library cache object handle所对应的library cache object的名称,例如如果是sql语句对应的库缓存对象句柄,则属性name就是该sql语句的sql文本;如果是表对应的库缓存对象句柄,则属性name就是该表的表明
属性“Namespace“:表示的是库缓存对象句柄对应的库缓存对象所在的分组名,不同类型的库缓存对象句柄可能属于同一个分组,比如sql语句和pl/sql语句所对应的库缓存对象句柄的namespace值都是CRSR
属性 “heap 0 pointer”:这里要说明下library cache object handle类似c语言的结构体,library cache object handle中还嵌套了一些子结构,其中heap 0 pointer是指向子结构heap 0的指针
heap 0也是一种复杂的结构,它一样有很多属性,对于cursor而言比较重点的两个属性是tables和data block pointer。
属性table记录的是于该heap 0所在的库缓存对象有关联关系的库缓存对象句柄地址的集合,table又细分为很多类,对于cursor而言重点关注child table,child table记录的就是从属于该heap 0所在的库缓存对象的子库缓存对象句柄地址的集合,简单来讲可以理解为指向子游标的库缓存对象句柄的指针,那么oracle就可以直接通过访问库缓存对象(parent cursor)句柄的heap 0中指定的child table,来直接找到相关的子库缓存对象(child cursor)句柄,进而访问子库缓存对象。
属性data block pointer是heap 0存储的指向data heap的指针,data heap可以简单理解为库缓存中的一块连续的内存区域,而这些内存区域就是存储着cursor的动态运行时runtime数据,比如特别常见的执行计划、sql所涉及的对象定义、绑定变量类型和长度等。
2 找到合适的hash bucket后,就去这个hash bucket对应的library cache object handles链表中找到是否有满足条件的library cache object handle(这里需要检验sql文本或者pl/sql文本是否一致,因为不同的sql语句或者pl/sql语句的hash value可能一致)
3 根据找到的library cache object handle也就是parent cursor对应的库缓存对象句柄去找对应的child cursor,最后看是否满足重用执行计划和解析数(要比对对象、绑定变量类型和长度等)
那么对于shared pool而言硬解析就有以下两种情况: 1 parent cursor和child cursor都没有办法共享 2 parent cursor能够共享,但是child cursor不能共享
可能在刚开始我们第一次接触oracle部分书籍和文档时就提到了shared pool中的library cache,但是真正能够讲清楚shared cursor、child cursor、hash bucket、library cache、library cache object、软解析、硬解析得并不多,当然这些概念模棱两可并不太影响我们运维的工作,但是如果能真正理解这些概念是可以帮助我们更深入的理解oracle的sql解析部分
跟shared cursor所不同的还是有以下几点:
由于session cursor概念的引入,oracle的解析需要增加这一步骤:首先计算hash value查找session cursor中是否有满足条件的session cursor,如果有满足条件的session cursor,则重用这个session cursor,如果没有满足条件的session cursor,则需要重新生成一个session cursor,对于session cursor而言,这个也属于硬解析,如果session cursor、parent cursor、child cursor都已经分别存在了PGA和library cache中,则这就是我们所提到的软软解析,软软解析不需要再次生成session cursor,相比软解析消耗更少的资源和时间。
接下来我们来验证下session cursor缓存到pga的条件:
SQL> show parameter session_cached_cursors;
NAME TYPE VALUE
------------------------------------ ----------- ------------------------------
session_cached_cursors integer 50
SQL> select count(*) from t_samp01;
COUNT(*)
----------
0
SQL> select cursor_type,sql_id from v$open_cursor where sid=50 and sql_text like 'select count(*) from t_samp01%';
no rows selected
SQL> select count(*) from t_samp01;
COUNT(*)
----------
0
SQL> select cursor_type,sql_id from v$open_cursor where sid=50 and sql_text like 'select count(*) from t_samp01%';
no rows selected
SQL> select count(*) from t_samp01;
COUNT(*)
----------
0
SQL> select cursor_type,sql_id from v$open_cursor where sid=50 and sql_text like 'select count(*) from t_samp01%';
CURSOR_TYPE SQL_ID
---------------------------------------------------------------- -------------
DICTIONARY LOOKUP CURSOR CACHED 16099tj19y4gr
SQL> select count(*) from t_samp01;
COUNT(*)
----------
0
SQL> select cursor_type,sql_id from v$open_cursor where sid=50 and sql_text like 'select count(*) from t_samp01%';
CURSOR_TYPE SQL_ID
---------------------------------------------------------------- -------------
SESSION CURSOR CACHED 16099tj19y4gr
SQL> select sql_text from v$sql where sql_id='16099tj19y4gr';
SQL_TEXT
--------------------------------------------------------------------------------
select count(*) from t_samp01
看见同一个session下执行3次以上的sql对应的session cursor已经缓存到了pga中
在oracle 11g之前的办法,在缓存session cursor的hash表对应的hash bucket中,oracle会缓存目标sql对应的parent cursor的库缓存对象句柄地址,这意味着oracle已经建立起了session cursor到parent cursor的联系,这样软软解析会对相关的latch的争用更低,因为session cursor中存储了直接指向parent cursor的指针,oracle不再需要和软解析一样要去持有library cache latch访问相关的hash bucket的library cache object handles链表中查找匹配的parent cursor
在oracle 11g后,dump session的信息,session cursor中已经没有记录,对应的parent cursor的library cache object handle地址:
11.2.0.3版本下alter sssion set events ‘immediate trace name errorstack level 3’的trac文件session cached cursor的dump中已经不存储指向parent cursor中的library cache object handle地址
11.2.0.3版本的trace文件:
----- Session Cached Cursor Dump -----
----- Generic Session Cached Cursor Dump -----
-----------------------------------------------------------
-------------- Generic Session Cached Cursors Dump --------
-----------------------------------------------------------
hash table=0x7feac43941d0 cnt=6 LRU=0x7feac4386678 cnt=6 hit=10 max=50 NumberOfTypes=6
type#0 name=DICTION count=0
type#1 name=BUNDLE count=5
type#2 name=SESSION count=1
type#3 name=PL/SQL count=0
type#4 name=CONSTRA count=0
type#5 name=REPLICA count=0
Bucket#024 seg=0x7feac4394648 nit=5 nal=5 ips=5 sz=56 flg=3 ucnt=1
0 cob=0x7feac43021f8 idx=18 flg=0 typ=1 cur=0x7feac4302328 lru=1 fl=15
Bucket#056 seg=0x7feac4394c48 nit=5 nal=5 ips=5 sz=56 flg=3 ucnt=1
0 cob=0x7feac42db1e8 idx=38 flg=0 typ=1 cur=0x7feac42db318 lru=1 fl=15
Bucket#130 seg=0x7feac4395a28 nit=5 nal=5 ips=5 sz=56 flg=3 ucnt=1
0 cob=0x7feac43a1f78 idx=82 flg=0 typ=1 cur=0x7feac43a20a8 lru=1 fl=15
Bucket#183 seg=0x7feac4396418 nit=5 nal=5 ips=5 sz=56 flg=3 ucnt=1
0 cob=0x7feac43abcd8 idx=b7 flg=0 typ=1 cur=0x7feac43abe08 lru=1 fl=15
Bucket#187 seg=0x7feac43964d8 nit=5 nal=5 ips=5 sz=56 flg=3 ucnt=1
0 cob=0x7feac43ac3f8 idx=bb flg=0 typ=1 cur=0x7feac43ac528 lru=1 fl=15
Bucket#192 seg=0x7feac43965c8 nit=5 nal=5 ips=5 sz=56 flg=3 ucnt=1
0 cob=0x7feac43043b8 idx=c0 flg=0 typ=2 cur=0x7feac43027b0 lru=1 fl=1
。。。
10g的版本trace文件:
这里会记录hdl就是session对应的library cache object handle的地址。
Session cached cursors
-----------------------------------------------------------
-------------- Generic Session Cached Cursors Dump --------
-----------------------------------------------------------
hash table=0xb7f31d00 cnt=3 LRU=0xb7f273f8 cnt=3 hit=4 max=20 NumberOfTypes=3
type#0 name=KQD count=1
type#1 name=KQD BUN count=0
type#2 name=KKS count=2
Bucket#056 seg=0xb7f323f4 nit=4 nal=4 ips=4 sz=16 flg=3 ucnt=1
0 cob=0xb7f39d80 38 flg=0 typ=0 idx=38 cur=0xb7f39b9c lru=1 flg=5 hdl=0x34cb963c
1 cob=0xb7f39d90 0 flg=0 typ=0 idx=0 cur=(nil) lru=0 flg=0 hdl=(nil)
2 cob=0xb7f39da0 0 flg=0 typ=0 idx=0 cur=(nil) lru=0 flg=0 hdl=(nil)
3 cob=0xb7f39db0 0 flg=0 typ=0 idx=0 cur=(nil) lru=0 flg=0 hdl=(nil)
Bucket#168 seg=0xb7f331f4 nit=4 nal=4 ips=4 sz=16 flg=3 ucnt=1
0 cob=0xb7f3b02c a8 flg=0 typ=2 idx=a8 cur=0xb7f4e2c0 lru=1 flg=1 hdl=0x34d8a490
1 cob=0xb7f3b03c 0 flg=0 typ=0 idx=0 cur=(nil) lru=0 flg=0 hdl=(nil)
2 cob=0xb7f3b04c 0 flg=0 typ=0 idx=0 cur=(nil) lru=0 flg=0 hdl=(nil)
3 cob=0xb7f3b05c 0 flg=0 typ=0 idx=0 cur=(nil) lru=0 flg=0 hdl=(nil)
Bucket#205 seg=0xb7f33694 nit=4 nal=4 ips=4 sz=16 flg=3 ucnt=1
0 cob=0xb7f3b0fc cd flg=0 typ=2 idx=cd cur=0xb7f3b1b8 lru=1 flg=1 hdl=0x347beec8
1 cob=0xb7f3b10c 0 flg=0 typ=0 idx=0 cur=(nil) lru=0 flg=0 hdl=(nil)
2 cob=0xb7f3b11c 0 flg=0 typ=0 idx=0 cur=(nil) lru=0 flg=0 hdl=(nil)
3 cob=0xb7f3b12c 0 flg=0 typ=0 idx=0 cur=(nil) lru=0 flg=0 hdl=(nil)
注意:解析执行sql时首先获取library cache latch,在执行sql时为了防止sql对应的cursor被修改,则需要将这个sql相关的library cache对象pin到内存中,这个过程是持有library cache pin的过程,而在oracle11g后,持有library cache latch和library cache pin的过程已经被mutex所代替。
cursor_space_for_time参数可以一定程度的解决库缓存的latch争用,当将此参数设置为true时,sql执行完毕后oracle也不会释放掉该sql相关的library cache pin,而是要等待游标关闭后才会释放掉相关sql的library cache pin,但是由于部分执行完毕的sql对应的child cursor并不能马上被age out出shared pool,从而导致shared pool的空间压力。
Shared SQL areas are kept pinned in the shared pool. As a result, shared SQL areas are not aged out of the pool as long as an open cursor references them. Because each active cursor’s SQL area is present in memory, execution is faster. However, the shared SQL areas never leave memory while they are in use. Therefore, you should set this parameter to true only when the shared pool is large enough to hold all open cursors simultaneously.
In addition, a setting of true retains the private SQL area allocated for each cursor between executions instead of discarding it after cursor execution, saving cursor allocation and initialization time.
false
Shared SQL areas can be deallocated from the library cache to make room for new SQL statements.
shared pool的内部结构远远比上面所列的要复杂,对于有些概念xiaoyu也不是理解的非常清晰,有兴趣的可以去看看相应的DSI部分。
原文地址:共享池部分-library cache、library cache object handle、li, 感谢原作者分享。