Skip to content

未分类 - 4. page

ORA-4031错误
ORA-04031错误就是因不能在分配连续的内存,可能是共享池内存碎片严重,也可能是确实内存不足。
引起这种情况的原因有:频繁更解析–需要内存空间多,并且容易产生更严重的内存碎片。
session_cached_cursors太高,被缓存的游标过多–占用大量library cache内存,有可能引发ORA-4031。

共享池碎片产生举例:
在报ORA-4031错误的时候,有可能使用下面的SQL语句查看,发现可用的内存还是足够大的,
SQL> select POOL,NAME,BYTES from v$sgastat whereNAME=’free memory’;
事实上,在Oracle发出4031错误之前,已经释放了不少recreatable类型的chunk了,因此会产生很多可用内存。但是这些可用的chunk中,没有一个chunk能够以连续的物理内存提供所需的内存空间
在shared pool中有一块保留区域,通过参数shared_pool_reserved_size设置,默认是shared pool空间的5%。
SQL>show parameter shared_pool_reserved_size
SQL>select request_misses from v$shared_pool_reserved;
这个参数反映了无法从保留区域获得足够大空间的chunk的总次数,尽量让这个参数为0.
对于非常大的对象,一般从这个区域中分配空间
这是一块独立管理的区域,这个区域中的chunk不会挂接到普通区域的链表中,普通区域的chunk也不会挂接到这个区域的链表中

SQL语句要缓存在共享池CHUNK中,假设SQL语句的文本、执行计划共需要4K。
在找可用CHUNK时,首先进入相应bucket进去查找,
如未找到4K大小CHUNK,则转向下一个非空bucket,假设找到一个5K的CHUNK;
此时会4K用来存放此SQL语句相关文本、执行计划,剩余1K成为一个新CHUNK并进入相应的bucket,及FREE LIST列表。
长此以往,可能产生大量1K/2K等小CHUNK,总空间很大,但是如果SQL语句需要比如4K的CHUNK,就无法请求到所需的CHUNK,产生共享池碎片,引起ORA-04031错误。
查看共享池中CHUNK SIZE情况,如果<1K比较多,可能就碎片严重。 —通常每个bucket上的chunk多于2000个,就认为共享池碎片过多。
col sga_heap format a15
col size format a10
select KSMCHIDX “SubPool”, ‘sgaheap(‘||KSMCHIDX||’,0)’sga_heap,ksmchcom ChunkComment,
decode(round(ksmchsiz/1000),0,’0-1K’, 1,’1-2K’, 2,’2-3K’,3,’3-4K’,
4,’4-5K’,5,’5-6k’,6,’6-7k’,7,’7-8k’,8,
‘8-9k’, 9,’9-10k’,’> 10K’) “size”,
count(*),ksmchcls Status, sum(ksmchsiz) Bytes
from x$ksmsp
where KSMCHCOM = ‘free memory’
group by ksmchidx, ksmchcls,
‘sga heap(‘||KSMCHIDX||’,0)’,ksmchcom, ksmchcls,decode(round(ksmchsiz/1000),0,’0-1K’,
1,’1-2K’, 2,’2-3K’, 3,’3-4K’,4,’4-5K’,5,’5-6k’,6,
‘6-7k’,7,’7-8k’,8,’8-9k’, 9,’9-10k’,’> 10K’);
###################

前台进程在共享池中查找CHUNK步骤:
1.首先查找子堆 free list
2.查找子堆lru
3.从父堆中分配chunk,做为子堆新 extent
4.父堆查找free list
5.父堆查找LRU
6.使用hide free space
7.如以上步骤失败,报0RA-04031
父堆需要持有shared pool latch
子堆的操作,有mutex / library cache pin保护

模拟ORA-04031错误:
首先要将修改open_cursors 参数
BYS@ bys3>show parameter cursors
NAME TYPE VALUE
———————————— ———– ——————————
open_cursors integer 50
session_cached_cursors integer 2
BYS@ bys3>alter system set open_cursors =50000;
System altered.
BYS@ bys3>show parameter shared_pool
NAME TYPE VALUE
———————————— ———– ——————————
shared_pool_reserved_size big integer 7M
shared_pool_size big integer 176M
重新登陆会话:
只打开游标,不关闭:select deptno from dept where deptno= 这语句的对象字段要能执行
declare
msql varchar2(100);
mcur number;
mstat number;
jg varchar2(2000);
cg number;
begin for i in 1..10000 loop
mcur:=dbms_sql.open_cursor;
msql:=’select deptno from dept where deptno=’||i;
dbms_sql.parse(mcur,msql,dbms_sql.native);
mstat:=dbms_sql.execute(mcur);
end loop;
end;
/
报错:
declare
*
ERROR at line 1:
ORA-04031: unable to allocate 16 bytes of shared memory (“sharedpool”,”unknownobject”,”SQLA”,”tmp”)
ORA-06512: at “SYS.DBMS_SQL”, line 1199
ORA-06512: at line 10
也可能报错:主要是unable to allocate1040 bytes 这里的有时不一样。上一个16bytes可能是语句确实需要16字节,但是从父堆分配区,需要按一个CHUNK分配,具体是多大CHUNK,没显示出来。
declare
*
ERROR at line 1:
ORA-04031: unable to allocate 1040 bytes of shared memory (“sharedpool”,”select
o”,”PLDIA^191e0a8d”,”PAR.C:parapt:Page”)
ORA-06508: PL/SQL: could not find program unit being called:”SYS.DBMS_SQL”
ORA-06512: at line 8
执行其它查询也报错:
BYS@ bys3>select * from dept where deptno=44;
select * from dept where deptno=44
*
ERROR at line 1:
ORA-00604: error occurred at recursive SQL level 2
ORA-04031: unable to allocate 136 bytes of shared memory (“sharedpool”,”select /*+ rule */
bucket_cn…”,”SQLA^337fc737″,”kccdef: qkxrMemAlloc”)

Elapsed: 00:00:10.99
BYS@ bys3>show parameter shared_pool
ORA-04031: unable to allocate 16 bytes of shared memory (“sharedpool”,”unknown
object”,”KGLH0^92c529c4″,”kglHeapInitialize:temp”)

警告日志中也可以看到大量的报错日志:
Mon Feb 03 20:20:44 2014
Errors in file /u01/diag/rdbms/bys3/bys3/trace/bys3_mmon_10113.trc (incident=138413):
ORA-04031: unable to allocate 16 bytes of shared memory (“sharedpool”,”unknownobject”,”KGLH0^ca490471″,”kglHeapInitialize:temp”)
Use ADRCI or Support Workbench to package the incident.
See Note 411.1 at My Oracle Support for error and packaging details.
Errors in file /u01/diag/rdbms/bys3/bys3/trace/bys3_mmon_10113.trc (incident=138414):
ORA-04031: unable to allocate 16 bytes of shared memory (“sharedpool”,”unknownobject”,”KGLH0^ca490471″,”kglHeapInitialize:temp”)
Use ADRCI or Support Workbench to package the incident.
See Note 411.1 at My Oracle Support for error and packaging details.
[oracle@bys3 ~]$ tail -n 50 alert_bys3.log
Mon Feb 03 20:20:14 2014
Errors in file /u01/diag/rdbms/bys3/bys3/trace/bys3_m000_10679.trc (incident=134643):
ORA-04031: unable to allocate 16 bytes of shared memory (“sharedpool”,”unknownobject”,”KKSSP^37″,”kglseshtSegs”)
Use ADRCI or Support Workbench to package the incident.
See Note 411.1 at My Oracle Support for error and packaging details.
Errors in file /u01/diag/rdbms/bys3/bys3/trace/bys3_m000_10679.trc:
ORA-04031: unable to allocate 16 bytes of shared memory (“sharedpool”,”unknownobject”,”KKSSP^37″,”kglseshtSegs”)
…………………………
Errors in file /u01/diag/rdbms/bys3/bys3/trace/bys3_cjq0_10175.trc:
ORA-00604: error occurred at recursive SQL level 1
ORA-04031: unable to allocate 528 bytes of shared memory (“sharedpool”,”PROPS$”,”PLDIA^191e0a8d”,”PAR.C:parapt:Page”)

4031错误临时解决方案是:杀掉一部分会话或者flush shared_pool;
SYS@bys3>select sid,count(*) from v$open_cursor group by sid;
SID COUNT(*)
———- ———-
30 7
1 2
28 1
13 3
31 4
14 2
35 3014
33 3
15 7
16 5
select sid,machine from v$session;
根据查出的机器来划分,KILL掉不太重要的会话

以SYS登陆,做flushshared_pool;
—不建议,刷新共享池后,所有的SQL语句都需要重新解析,对共享池中LATCH的争用,以及大量更解析会消耗大量CPU资源。
SYS@ bys3>alter system flush shared_pool;
System altered.
但是之后会面临大量正常SQL语句的第一次执行的硬解析。。
过后仍需要找出产生大量硬解析的SQL语句进行优化。

共享池之十:模拟ORA-4031错误

解析分为硬解析和软解析和软软解析,SQL语句第一次解析时必须进行硬解析

还有一种是结果集缓存—无解析,详见:结果集缓存

一句话说明硬解析与软解析的区别是:

硬解析=需要生成执行计划 软解析=不需要生成执行计划

在Oracle中存在两种类型的SQL语句,一类为DDL语句,不共享使用,也就是每次执行都需要进行硬解析。还有一类就是DML语句,会进行硬解析或软解析。

硬解析变成软解析:绑定变量

软解析变成软软解析:设置session_cached_cursors,详见本文最后。

软软解析参数session_cached_cursors的参考值
select owner,name from v$db_object_cache where child_latch=1;显示library cache中那些对象被缓存,以及对象的尺寸

session_cached_cursors占用的内存:会话退出会释放,或者达到达到最大值后,最早、早少使用的会被释放。

session_cached_cursors参数的设置: –来自周亮–ORACLE DBA实战攻略。

SYS@ bys3>show parameter session_cached 11G中默认值是50

NAME TYPE VALUE

—————————————————————————–

session_cached_cursors integer 50

SYS@ bys3>select a.name,b.value from v$statname a,v$sesstat b where a.statistic#=b.statistic# and a.name in(‘session cursor cache hits’,’session cursor cache count’,’parse count (total)’) and b.sid=(select c.sid from v$mystat c where rownum=1);

NAME VALUE

————————————————————————–

session cursor cachehits 32

session cursor cachecount 4

parse count(total) 43

session cursor cache count表示指定会话缓存的游标数,session_cached_cursors参数是系统当前每个会话最多能缓存的游标数。

session cursor cache count小于session_cached_cursors,不用增加session_cached_cursors大小。如相等,则有可能需要增加。

session cursor cache hits 表示从UGA中命中的次数–软软解析次数。

parse count (total)指定会话的总解析次数。

如果session cursor cache hits接近parsecount (total),无需调整session_cached_cursors。

如果session cursor cache hits远小于parsecount(total),则可能需要调整session_cached_cursors。

session_cached_cursors对所有会话生效,如果需要调优的会话占所有会话比例很小,调整意义不大。

–注意session_cached_cursors是静态参数,调整后要重启库才生效。

SYS@ bys3>alter system set session_cached_cursors=11;
alter system set session_cached_cursors=11
*
ERROR at line 1:
ORA-02096: specified initialization parameter is not modifiable with this option

绑定变量
oracle 能够重复利用执行计划的方法就是采用绑定变量。

绑定变量的实质就是用于替代sql语句中的常量的替代变量。绑定变量能够使得每次提交的sql语句都完全一样。

绑定变量只是起到占位的作用,同名的绑定变量并不意味着在它们是同样的,在传递时要考虑的是传递的值与绑定变量出现顺序的对位,而不是绑定变量的名称。

绑定变量是在通常情况下能提升效率,非正常的情况如下:

在字段(包括字段集)建有索引,且字段(集)的集的势非常大(也就是有个值在字段中出现的比例特别的大)的情况下,使用绑定变量可能会导致查询计划错误,因而会使查询效率非常低。这种情况最好不要使用绑定变量。

但是并不是任何情况下都需要使用绑定变量,下面是两种例外情况:

1.对于隔相当一段时间才执行一次的SQL语句,这是利用绑定变量的好处会被不能有效利用优化器而抵消

2.数据仓库的情况下。

绑定变量不能当作嵌入的字符串来使用,只能当作语句中的变量来用。不能用绑定变量来代替表名、过程名、字段名等.

从效率来看,由于oracle10G全面引入CBO,因此,在10G中使用绑定变量效率的提升比9i中更为明显。

绑定变量窥视:Bind Peeking–字段分布均匀时有利
Bind Peeking 就是当在WHERE条件中使用绑定变量的时候,CBO会根据第一次使用的真实变量值来生成一个执行计划。在这个cursor的整个生命周期中,CBO不会再对相同的SQL进行hardparse。

优点:如果索引字段的值是均匀分布的,hardparse就降低了,性能提高。

缺点:如果字段分布不均匀,并且第一次使用值不具有普遍性,那么执行计划就将非常糟糕。

Oracle11g 提供了一个新特性,AdpativeCursorSharing,或者叫 Extended Cursor Sharing,来解决这个问题。他的核心思想是,当某个字段的histogram提供了数据不均匀的信息,CBO会在实际使用不同值的时候,尝试重新生成更合适的执行计划。

通过隐含的参数来调整数据库默认的bind peeking行为:_OPTIM_PEEK_USER_BINDS。

关闭Bind Variable Peeking,可以设置该参数为False —-要重启数据库。

SQL>alter sessionset”_optim_peek_user_binds”=false

绑定变量分级–bind graduation及bind-mismatch导致高版本问题
bind_mismatch一般是由于bind value的长度不同导致bindbuffer无法重用,最终导致cursor无法重用。
根本的原因在于:Oracle数据库引擎应用了绑定变量分级,即根据绑定变量的长短划分为4级,比如varchar2(32)和varchar2(33)属于不同级别。
四个级别的划分是:
0~32
32~128
129~2000
2001~
当表上有数十上百个varchar2类型的列时候,会比较常见因为bind graduation导致的bind-mismatch,即产生N多无法共享的子游标。
子游标过多会对SQL parse有影响。
针对一些特别的表或者查询列特别多的SQL,可以通过给字符串变量绑定固定的长度,如to_char(4000),来避免因为bind graduation导致child cursor过多的问题.

例 如:对于字符类型的字段,进行绑定变量的时候,第一次会使用32字节的BUFFER,如果该值小于32字节的话,第二次执行这个SQL的时候,如果小于 32字节,那么可以共享这个CURSOR,如果大于,就无法共享,原因就是BIND_MISMATCH,此时会产生一个子CURSOR,同时分配128字节的BIND BUFFER,以此类推。
select count(*) from v$sql_shared_cursor where sql_id=’9rwd4wkwm4bsy’ andBIND_MISMATCH=’Y’ ;
COUNT(*)
———-
120

可以通过v$sql_bind_capture视图查看一下每次绑定变量的值:
select position,LAST_CAPTURED,datatype_string,value_string fromv$sql_bind_capture where sql_id=’9rwd4wkwm4bsy’ and rownum<50;

正常情况不会产生这么大量的子CURSOR。但是由于一些BUG,会导致问题。
如果没有补丁,一个临时性的解决方案,设置一个较大的BUFFER
SQL>ALTER SESSION SET EVENTS ‘10503 trace name context level<bufferlength>, forever’;

而这些具体的内容,可以通过视图来查看。查看上述的共享父游标对于的bind_metadata
selects.child_number,m.position,m.max_length,
decode(m.datatype,1,’VARCHAR2′,2,’NUMBER’,m.datatype)as datatype
from v$sql s,v$sql_bind_metadata m
where s.sql_id=’94ka9mv232yxb’
and s.child_address=m.address;
CHILD_NUMBER POSITION MAX_LENGTH DATATYPE
———— ———- ———————————————-
0 3 32 VARCHAR2
0 2 32 VARCHAR2
0 1 22 NUMBER
1 3 32 VARCHAR2
1 2 128 VARCHAR2
1 1 22 NUMBER
从绑定变量四个级别来看,最多生成4个子游标。但是为什么AWR报表中SQL ordered by Version Count的version count能高达好几十,甚至几百呢?而且不能共享的原因都是因为bind_mismatch.

关于:cursor_sharing
根据oracle官方建议在11g中不推荐使用cursor_sharing=SIMILAR,其实在所有版本中都不推荐,设置为该值很容易导致高版本问 题.而且该值会出现莫名其妙的,无法解释的高版本问题.而且根据oracle相关文档,在即将发布的12c版本中,将除掉SIMILAR值.对于客户库的 该问题,因为很多sql未绑定参数,为了减少硬解析,建议在业务低谷时设置cursor_sharing=FORCE,并刷新sharedpool.

如果cursor_sharing 参数是设置为similar的,这样会将SQL 中的谓词值自动用变量来代替。这样会增加cursor的数量。
为了减少cursor对library cache的占用,先将cursor_shring 参数改成了默认的exact模式。
这样version_count 会减少很多,但是硬解析的次数也会增加,可能会增加Library Cache Latch等待。
cursor_sharing的实验可以参考DAVE的博客:http://blog.csdn.net/tianlesoftware/article/details/6551723

共享池之九:绑定变量与session_cached_cursors

先来张大图:

结合上图来说明一下解析的各个步骤涉及的锁。

软解析、硬解析、软软解析区别的简单说明:
为了将用户写的sql文本转化为oracle认识的且可执行的语句,这个过程就叫做解析过程。

解析分为硬解析和软解析,SQL语句第一次解析时必须进行硬解析

一句话说明硬解析与软解析的区别是:
硬解析=需要生成执行计划 软解析=不需要生成执行计划

在Oracle中存在两种类型的SQL语句,一类为DDL语句,不共享使用,也就是每次执行都需要进行硬解析。还有一类就是DML语句,会进行硬解析或软解析。

硬解析变成软解析:绑定变量

软解析变成软软解析:设置session_cached_cursors,详见

图中涉及的各结构简单介绍:
涉及的各结构的简单介绍: 详见:

父游标:保存HASH值,SQL文本–相同SQL语句,就只有一个父游标

父游标里主要包含两种信息:sql文本以及优化目标。父游标在第一次打开时被锁定,直到其他所有的session都关闭该游标后才被解锁。当父游标被锁定的时候是不能被交换出librarycache的,只有在解锁以后才能被交换出library cache。父游标被交换出内存时父游标对应的所有子游标也被交换出library cache。

子游标:一个父游标下会有多个子游标,各个子游标的执行计划不一样–多版本.一个父下必有一个子游标,可以有多个子游标。

子游标包括游标所有的信息,比如具体的执行计划、绑定变量等。子游标随时可以被交换处library cache,当子游标被交换出library cache时,oracle可以利用父游标的信息重新构建出一个子游标出来,这个过程叫做reload(重载)。

父HANDLE,里面有父游标堆0的地址。。

父游标堆0:有指向一个或多个子游标的HANDLE够句柄地址

子游标的HANDLE:有子游标堆0地址

子游标堆0:有SQL语句依赖关系,并指向子游标的堆6

子游标堆6:存有SQL语句的执行计划

SQL语句在Library cache执行的第一次检查过程:
1.通过语法语义权限等检查的SQL语句进入Library cache
2.将SQL文本转化为ASCII值(大小写ASCII不同)并进行hash函数的运算
4.得到一个HASH值对应到hash bucket的号码
################以上检查通过后,进入以下解析过程

软软解析:
–通过设置session_cached_cursors参数实现-
SQL执行=3次(可以不是一个会话执行的SQL),堆6的DS-堆描述符地址被放入UGA(属于PGA)–LOCK变为1-NULL标记语句为缓存并保证内存不被释放(堆6释放堆0才能释放)。
也就是SQL执行3次,被缓存。第四次,就是软软解析了。
–优化目标:命中率90%以上。
会话发起SQL,会首先在User Global Area中查找CURSOR信息。
此时,在父游标handle,子游标handle和子游标堆6上使用NULL 1。

####################################

软解析:
1.获得library cacheLatch —如未获得将产生:Latch:library cache
2.获得library cache lock,检索bucket上的父游标handle,得到所指向的父游标堆0-LCO的内存地址。
3.获得library cache pin,读取父游标堆0-LCO,得到子游标handle地址。
4.获得library cache lock,检索子游标handle,得到所指向的子游标堆0-子LCO的内存地址。
5.获得library cache pin,读取子游标堆0-子LCO从而得到子游标堆6地址。
6.读取子游标堆6,得到SQL执行计划。
###找到child lco后,增加parsecount(total)统计值。
SQL开始执行:此时以共享模式获得library cache lock和library cache pin,并执行SQL。
FETCH阶段:执行完成进入FETCH阶段,SQLCURSOR将library cache lock转换为null模式,释放library cache pin。
###############################################################

在尝试软解析时:
–如果未检索到相同的父游标LCO或子游标LCO时,发生硬解析。
–如果子游标堆6上不能加共享library cachepin或者child lco中信息不完整,需要重建执行计划–记录为硬解析。

硬解析:
如果未检索到相同的父游标LCO或子游标LCO时,发生硬解析。进程会一直持有library cache latch,直到硬解析结束为止。
1.获取shared pool latch,从freelist的bucket上查找合适大小的CHUNK。
不存在大小合适的CHUNK会分割大CHUNK,剩余的会再进入相应的BUCKET。
如 果不能从free list的bucket上查找到合适大小的CHUNK,则进入 lru list;如果仍不能获取到CHUNK,则从shared pool剩余内在中分配。如果CURSOR达到 _shared_pool_reserved_min_alloc隐含参数的大小标准(11.2.0.4中是4400),则从保留池中分配CHUNK;如 果这些分配CHUNK操作都失败,报错:ORA-04031。如bucket列表过长或者碎片严重,产生latch:shared pool争用。

2.分配到CHUNK后。获得library cachelock–独占模式,创建父游标handle
3.获得library cache pin,创建父游标堆0-父LCO的信息。–library cache lock转为NULL
4.获得library cache lock,创建子游标handle
5.获得library cache pin,创建子游标堆0-子LCO的信息。
6.library cache pin,创建子游标堆6-执行计划的信息(通过优化器创建一个最优的执行计划,这个过程会根据数据字典里面记录的对象的统计信息,来计算最优的执行计划,这一步涉及的运算量很大,最耗CPU资源)。
SQL开始执行:此时以共享模式获得library cache lock和library cache pin,并执行SQL。
FETCH阶段:执行完成进入FETCH阶段,SQLCURSOR将library cache lock转换为null模式,释放library cache pin。

关于MUTEX与图中librarycache Latch/PIN/LOCK的对应:
关于MUTEX,可以简单的把library cache Latch/PIN/LOCK当做MUTEX的不同模式来套入此步骤。

在10G中,Mutex主要保护 handle和LCO—替代library cache PIN/LOCK

在11G中,Mutex可以保护bufket上链表,handle和LCO—替代library cache Latch/PIN/LOCK

句柄上访问竞争:Cursor:mutex 堆的访问竞争:Cursor:pin

解析时MUTEX的相关争用

1、相关锁

(1)、计算HASH值,找到Bucket,搜索HASH链表,查找句柄。

LIbrary Cache Latch(11G后被Mutex取代)

(2)、在父游标句柄中查找父游标堆0

mutex(取代Library cache lock latch) ,Library cache lock

(3)、在父游标堆0中,查找子游标句柄。

两次mutex。两种类型的Mutex。取代了Librarycache pin latch和Library cache pin 。

(4)、在子游标句柄中,查找子游标堆0地址。

mutex(取代Library cache lock latch) ,Library cachelock

(5)、在子游标堆0中,查找子游标堆6地址。

一次mutex。取代了Librarycache pin latch和Library cache pin 。

(6)、在子游标堆6中,读取SQL执行计划。

一次mutex。取代了Librarycache pin latch和Library cache pin 。

 

共享池之八:软解析、硬解析、软软解析 详解一条SQL在library cache中解析涉及的锁

生成执行计划的过程:编译器:分为三部分:
2.优化器:–包括三个部分

查询转换器RBO–>CBO,目前是CBO ,optimizer_mode–ALL_ROWS参数值,适合OLTP。FIRST_ROWS_N适合分页,OLAP。

查询转化器:

视图合并–视图时直接用视图SQL语句对应表做基表进行连接。

谓词推进,子查询非嵌套化–相关子查询;OR–UNION合并

成本估算器:

拿数据字典里统计信息,主要有:

表:dba_tab_statistics –行数,块数

表中字段:dba_tab_col_statistics –选择率 selectivity 字段:number_distinct

索引:dba_ind_statistics 叶块 高度 聚簇因子

系统评估:CPU IO

数据字典本身:tab$,obj$,col$,con$

内部表:x$bh,x$ksmsp

计划生成器:访问路径–索引OR全表扫描,表连接的类型、顺序和方法

Oracle根据提交的SQL语句再查询相应的数据对象是否有统计信息。如果有统计信息的话,那么CBO将会使用这些统计信息产生所有可能的执行计划(可能多达成千上万个)和相应的Cost,最终选择Cost最低的那个执行计划。如果查询的数据对象无统计信息,则按RBO的默认规则选择相应的执行计划。这个步骤也是解析中最耗费资源的,因此我们应该极力避免硬解析的产生。

3.行源生成器:执行函数–对应执行计划中

4.执行引擎:

至此,解析的步骤已经全部完成,Oracle将会根据解析产生的执行计划执行SQL语句和提取相应的数据。

共享池之七:执行计划的生成过程

latch:library cache –desc v$librarycache;

latch:library cache用于保护hash bucket.
library cache lock保护HANDLE。
library cache pin保护library cache object–LCO.
从10G开始,library cache lock和library cache pin被MUTEX部分取代。暂时不讨论MUTEX。
latch:library cache的数量:
SYS@ bys3>select name from v$latch_children where name like ‘%librarycache%’;
隐含参数:_kgl_bucket_count,默认值大于等于系统中CPU个数的最小素数-不超过67。查询时会显示为0–BUG。
一个latch:library cache管理着多个librarycache buckets.

latch:library cache多是因为局部latch:library cache访问比较频繁,增大其数量并不能解决。
如果shared pool过小,也会引发librarycache latch竞争,进而引起shared pool latch竞争—参考AWR–Shared Pool Advisory
具有高version_count的SQL也容易导致latch:library cache,因为在搜索到子LCO前会一直持有latch:library cache。
#########

library cache lock保护HANDLE–父游标和子游标的handle

在硬解析时,需要以独占模式(EXCLUSIVE)持有librarycache lock和library cache pin。
进程访问LCO,首先需要在latch:librarycache的保护下获得library cache lock,才能访问和修改HANDLE;然后获取library cache pin,才能访问和LCO。
子游标的HANDLE和LCO的访问和上面一样。

MODE有三类: null 1;shared 2;exclusive 3;

null 1;空锁:空锁和独占锁互相不阻塞,主要起“标记”目的。标记对象正在使用中,或者标记对象以后还会用。保证对象内存不会被覆盖或释放。–可以执行三次,查看
select kglhdadr,kglhdpar,kglhdlmd,kglobhs0,kglobhd0,kglobhd6 from x$kglob wherekglnaobj like ‘select * from aaa’;
查看游标是否关闭。执行不大于3次,不会缓存,如有其它语句,则将未缓存的清空。
select * from bys.dept 执行三次,
SYS@ bys3>select kglhdadr,kglhdpar,kglhdlmd,kglhdpmd,kglobhs0,kglobhd0,kglobhd6from x$kglob where kglnaobj like ‘select * from bys.dept’;
KGLHDADR KGLHDPAR KGLHDLMD KGLHDPMD KGLOBHS0 KGLOBHD0 KGLOBHD6
——– ——– ———- ———- ———- ——– ——–
2499B1C0 24965DB4 1 0 4372 246C5CE0 252F0DD0 —-被缓存的子游标,
24965DB4 24965DB4 1 0 4500 23CC848C 00
被缓存的游标:当内存不足时,子游标堆6可以被覆盖,其它HADNLE等不可被覆盖。–原因是:重建执行计划的信息–父堆0,子堆0等都有可以快速重建执行计划-也算硬解析,但是消耗资源比正常硬解析少。

等待事件的P1 P2 P3分别是:

P1=HANDLE ADDRESS
P2=LOCK/PIN ADDRESS
PS=MODE*100+NAMESPACE
NAMESPACE分以下类型:
1.SQL AREA
2.TABLE/PROCEDURE/FUNCTION/PACKAGE HEADER
3.PACKAGE BADY
4.TRIGGER
5.INDEX
6.CLUSETER
7.PIPE
13.JAVA SOURCE
14.JAVE RESOURCE
32.JAVA DATA

常见的library cache lock持有模式的情况:

以独占持有的语句是:
ALTER TABLE……,
CREATE OR REPLACE PROCEDURE;
共享模式持有:SQL解析阶段
在SQL执行阶段,由共享模式转换为NULL。
定位引起library cache lock等待事件的语句:
select b.sid from x$kgllk a,v$session b where a.kgllkhdl in (select p1raw fromv$session_wait where wait_time=0 and event=’library cache lock’) and a.kgllkmod<>0and b.saddr=a.kgllkuse;

常见的library cache pin持有模式的情况:

以独占模式持有的是:
ALTER PROCEDURE ..COMPLE;
硬解析产生执行计划过程中需要
以共享模式持有的是:SQL执行阶段、PROCEDURE执行阶段。
定位引起library cache pin等待事件的会话:
select a.sid from x$kglpn b,v$session a where b.kglpnhdl in (select c.p1rawfrom v$session_wait c where c.wait_time=0 and c.event like ‘library cachepin%’) and b.kglpnmod<>0 and a.saddr=b.kglpnuse;

共享池之六:shared pool latch/ library cache latch /lock pin 简介