ITPub博客

首页 > Linux操作系统 > Linux操作系统 > 从10046 Trace RAW File看Cursor

从10046 Trace RAW File看Cursor

原创 Linux操作系统 作者:realkid4 时间:2013-10-30 17:05:09 0 删除 编辑

 

游标共享CursorOracle学习过程中的一个重点和难点。OracleCursor是建立在对SQL解析Parse消耗的优化上的。根据不同的内存缓存结构,我们经常可以听到诸如:硬解析Hard Parse、软解析Soft Parse和软软解析的名词概念。

 

严格的说,游标共享的概念基础是游标。Oracle中,游标可以分为Shared CursorPrivate Cursor两个大的类型。理解游标的前提,一定要区分出这两个游标类型。

 

1Shared and Private Cursor

 

Shared Cursor大家谈的比较多,就是驻留在Library Cache里面的缓存对象,其中保存着之前解析好的执行计划。当一个SQL语句第一次出现在系统中,OracleLibrary Cache中没有找到对应的“现成”执行计划,就会启动硬解析Hard parse过程,在Library Cache中生成一个Shared Cursor注意:这个SQL Cursor可以被其他“符合游标共享条件”的其他会话session共享。在没有被age out或者flush出内存前,都是可以共享。如果第二次发出相同SQL语句,共享了Shared Cursor,我们称之为Soft Parse

 

而与Shared Cursor对应的就是Private CursorPrivate Cursor是驻留在Server ProcessPGA空间里的。当我们发出SQL或者手工创建一个Cursor,都会在Server Process对应的PGA空间里创建出一个Private Cursor对象。

 

顾名思义,Private Cursor的含义是只能被当前Session使用,不能实现session间共享。但是,相同一个Session,如果多次执行,是不是需要多次的创建Private Cursor呢?这个过程涉及到的问题就是Private Cursor的共享问题。

 

我们在一些资料里面可以看到一些混淆概念。说一个SQL只有执行三次之上,才能进行共享。如果我们进行简单的实验,就可以发现这个论断在shared cursor中并不成立。一旦SQL执行一次,在Library Cache中会去生成shared cursor,何来三次之说?应该说,这个论断前提是Private Cursor共享。

 

2、软软解析和参数配置

 

我们接触很多的概念是“Hard Parse”和“Soft Parse”。两者的差异在于是否在Library Cache中发生执行计划生成的动作。如果我们将Private Cursor因素考虑进去之后,就会有一个新的解析类型“软软解析”。

 

即使是Soft Parse,我们在PGA里面,每次执行SQL的时候都会有Private Cursor的创建过程。按照Cursor生命周期,当Cursor执行结束之后,会有一个Close动作将Private Cursor失效。Oracle是可以尝试对Private Cursor进行缓存,也就是说,Close动作并不是真正关闭消失,而是可以支持共享Private Cursor

 

如果可以实现Private CursorPGA中的重用,我们是可以将PGA中创建Cursor的部分成本消除掉。实现所谓的软软解析。

 

Oracle早期开始,我们接触过一个参数为open_cursor。最初这个参数起到两个层面作用,其一是控制一个会话可以同时打开的最大Cursor数量,另一个是控制了PGA里面能够共享Private Cursor缓存的最大个数。

 

之后Oracle的设置出现了一些变化,引入了新参数session_cached_cursors,单独进行缓存区大小的限制。目前笔者实验的版本中,这个参数是50

 

 

SQL> show parameter cached

 

NAME                                 TYPE        VALUE

------------------------------------ ----------- ---------------

session_cached_cursors               integer     50

 

 

对于PGA里面的Private Cursor共享情况,Oracle会记录生成的次数。当执行三次的时候,就会建立PGA内部缓存的结构机制。

 

本篇中我们使用10046来验证上面提到的机制。

 

3、环境准备

 

我们先找一个10046Trace文件作为实验对象。选择11.2.0.3作为实验对象。

 

 

SQL> select value from v$diag_info where name='Default Trace File';

VALUE

--------------------------------------------------------------------

/u01/app/diag/rdbms/ora11g/ora11g/trace/ora11g_ora_6964.trc

 

 

清空shared poolbuffer cache,执行相同的SQL语句10次。

 

 

SQL> alter system flush shared_pool;

系统已更改。

 

SQL> alter system flush buffer_cache;

系统已更改。

 

 

SQL> alter session set events '10046 trace name context forever, level 12';

会话已更改。

 

SQL> select count(*) from t;

  COUNT(*)

----------

         0

 

SQL> select count(*) from t;

  COUNT(*)

----------

         0

(其余执行次数略……

 

SQL> alter session set events '10046 trace name context off';

会话已更改。

 

SQL>

 

 

生成了trace文件之后,我们下面详细分析这个文件的细节。

 

4Trace RAW解析

 

Trace RAW文件记录了SQL执行过程中所有的细节内容,包括等待事件和执行计划。RAW文件重要之处在于其中包括了很多Recursive Call SQL细节,帮助我们分析每个步骤究竟发生了什么。

 

我们依次对10次执行相同SQL的过程进行分析和解释。首先是第一次SQL语句解析出现。

 

 

--第一次执行片段(开始部分)

=====================

PARSING IN CURSOR #106410908 len=22 dep=0 uid=0 ct=3 lid=0 tim=1382941437045398 hv=2763161912 ad='2e33bcc0' sqlid='cyzznbykb509s'

select count(*) from t

END OF STMT

PARSE #106410908:c=28996,e=28852,p=291,cr=85,cu=0,mis=1,r=0,dep=0,og=1,plh=2966233522,tim=1382941437045395

EXEC #106410908:c=0,e=36,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2966233522,tim=1382941437045585

WAIT #106410908: nam='SQL*Net message to client' ela= 6 driver id=1413697536 #bytes=1 p3=0 obj#=78127 tim=1382941437045636

 

 

注意几个细节:首先我们说中间的PARISING IN CURSOR表示Oracle开始启动解析过程,这个步骤SQL还没有被解析。SQL语句被赋予了一个数字编号:#106410908。这个时候,SQL语句还是文本样式。

 

PARSE步骤,Oracle实现了语句的Parse,注意,无论是Hard还是Soft Parse,都会有这个步骤和资源消耗,只是多少之分。其中mis=1>0,表示OracleLibrary Cache中没有找到对应的共享游标,于是只能重新进行Parse解析。这是一次硬解析过程,消耗时间为28852e=28852)。

 

对这个mis,我们要注意一下,即使不是Parse,也有可能出现mis>1的情况。这个时候,说明缓存的共享游标(shared pool)被age out出去,Oracle在执行中间需要重新进行硬解析步骤。

 

上面就是第一次执行的开始阶段,之后就是读块的动作,最后,我们看到了PGA里面Private Cursor关闭动作。

 

 

*** 2013-10-28 14:23:58.135

WAIT #106410908: nam='SQL*Net message from client' ela= 1074561 driver id=1413697536 #bytes=1 p3=0 obj#=78127 tim=1382941438135076

CLOSE #106410908:c=0,e=64,dep=0,type=0,tim=1382941438135689

 

 

关闭动作时体现PGA里面Private Cursor的表现。Shared Cursor只有Age outFlush的情况,而Private Cursor有关闭的动作,就如同我们在代码里面显示的进行cursor close

 

注意里面有一个重要取值typetype就用于表示关闭游标的操作类型。取值含义如下:

 

ü  0:表示游标从未被缓存且执行次数小于3次;

ü  1:该游标从未被缓存但是执行次数至少3次,如果此时PGA中还有缓存位置,也就是数量没有超过session_cached_cursor参数上线,就会被缓存;

ü  2:该游标从未被缓存但是执行次数至少3次,如果要进入缓存,需要将原有的旧缓存age out出去,注意是将PGA里面的缓存age out

ü  3:已经被缓存,交由缓存管理;

 

上面的取值规则,反映了Private Cursor的工作原则。第一次执行关闭动作type0,表示没有进入缓存,执行次数小于3次。

 

下面是第二次执行情况。

 

 

--第二次执行

=====================

PARSING IN CURSOR #106410908 len=22 dep=0 uid=0 ct=3 lid=0 tim=1382941438136083 hv=2763161912 ad='2e33bcc0' sqlid='cyzznbykb509s'

select count(*) from t

END OF STMT

PARSE #106410908:c=0,e=145,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2966233522,tim=1382941438136079

EXEC #106410908:c=0,e=95,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2966233522,tim=1382941438136254

WAIT #106410908: nam='SQL*Net message to client' ela= 7 driver id=1413697536 #bytes=1 p3=0 obj#=78127 tim=1382941438136300

 

 

第二次执行中依然有PARSING IN CURSOR动作和PARSE动作。形成了Cursor编号依然是106410908。但是注意PARSE部分中,mis=0,说明此时发生了Shared CursorLibrary Cache中的共享。而且从时间上看,e=145,远远小于第一次执行的消耗值。这次典型是一个Soft Parse动作。

 

第二次关闭游标记录。

 

 

*** 2013-10-28 14:23:59.071

WAIT #106410908: nam='SQL*Net message from client' ela= 926273 driver id=1413697536 #bytes=1 p3=0 obj#=78127 tim=1382941439071316

CLOSE #106410908:c=0,e=60,dep=0,type=0,tim=1382941439072000

 

 

第二次关闭cursor时候,type依然为0,由于是第二次,没有达到门限值。

 

第三次执行SQL,开头情况如下:

 

 

=====================

PARSING IN CURSOR #106410908 len=22 dep=0 uid=0 ct=3 lid=0 tim=1382941439072341 hv=2763161912 ad='2e33bcc0' sqlid='cyzznbykb509s'

select count(*) from t

END OF STMT

PARSE #106410908:c=0,e=126,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2966233522,tim=1382941439072337

EXEC #106410908:c=0,e=100,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2966233522,tim=1382941439072516

 

 

依然是存在PARSING IN CURSORPARSE动作。PARSE中的mis取值为0,时间e=126。这次依然是shared cursor中的软解析动作。

 

第三次关闭cursor情况如下:

 

 

*** 2013-10-28 14:23:59.871

WAIT #106410908: nam='SQL*Net message from client' ela= 789009 driver id=1413697536 #bytes=1 p3=0 obj#=78127 tim=1382941439871440

CLOSE #106410908:c=0,e=141,dep=0,type=1,tim=1382941439872393

 

 

Close动作中,type取值出现为1。根据注释信息,type=1表示当前Private Cursor没有在PGA缓存里面,但是已经出现了三次,如果PGA缓存有空间,就会进入缓存中。

 

第四次执行情况:

 

--第三次执行的结尾

WAIT #106410908: nam='SQL*Net message from client' ela= 789009 driver id=1413697536 #bytes=1 p3=0 obj#=78127 tim=1382941439871440

CLOSE #106410908:c=0,e=141,dep=0,type=1,tim=1382941439872393

--第四次执行的开头

PARSE #106410908:c=0,e=110,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2966233522,tim=1382941439872577

EXEC #106410908:c=0,e=109,p=0,cr=0,cu=0,mis=0,r=0,dep=0,og=1,plh=2966233522,tim=1382941439872723

WAIT #106410908: nam='SQL*Net message to client' ela= 59 driver id=1413697536 #bytes=1 p3=0 obj#=78127 tim=1382941439872829

 

 

第四次出现了比较大的差异,我们没有找到PARING IN CURSOR,只有Parse动作,mis=0除了说明进行了软解析之外,也说明此次Private Cursor也是在共享,没有出现重新ParsePrivate Cursor的情况,也就是出现“软软解析”。

 

 

结尾中的close动作,也是如此表示的。

 

 

WAIT #106410908: nam='SQL*Net message from client' ela= 854440 driver id=1413697536 #bytes=1 p3=0 obj#=78127 tim=1382941440735702

CLOSE #106410908:c=0,e=79,dep=0,type=3,tim=1382941440736504

 

 

此时的type取值为3,说明当前这个游标已经进入缓存结构,被共享。

 

此后第五到最后一次的情况均和第四次执行相同,都是没有PARSING IN CURSOR,只有PARSE动作,结尾close游标的时候type=3。具体篇幅原因,代码片段省略。

 

5、结论

 

通过上面的实验,我们可以得到关于shared cursorprivate cursor的机制。

 

首先,如果SQL执行中,没有找到对应的shared cursor执行计划,重新生成执行计划,这个过程就是硬解析。一旦执行计划被生成,就可以被共享,不存在三次之说。如果shared pool中存在对应的执行计划shared cursor,执行被称为soft parse软解析。

 

对于Private Cursor,如果连续执行三次以上,该语句的Private Cursor就可以缓存在PGA里面,以后再次执行的时候就可以进行共享,也就是软软解析。

 

来自 “ ITPUB博客 ” ,链接:http://blog.itpub.net/17203031/viewspace-775379/,如需转载,请注明出处,否则将追究法律责任。

请登录后发表评论 登录
全部评论
求道~

注册时间:2010-11-30

  • 博文量
    545
  • 访问量
    7630596