scott@MYDB>select plan_hash_value,child_number from v$sql where sql_id='78bd3uh4a08av';
PLAN_HASH_VALUE CHILD_NUMBER
--------------- ------------
3956160932 0
3956160932 1
注意到上述SQL在V$SQL中有两条匹配记录,且这两条记录的CHILD_NUMBER的值分别为0和1,说明Oracle在执行上述SQL时确实产生了两个Child Cursor,它们的子游标号分别为0和1.
Oracle在解析目标SQL时去库缓存中查找匹配Shared Cursor的���程实际上是在依次顺序执行如下步骤:
(1)根据目标SQL的SQL文本的哈希值去库缓存中找匹配的Hash Bucket。注意,更准确的说,这里的哈希运算是基于对应库缓存对象句柄的属性Name和Namespace的值的,只不过对于SQL语句而言,其对应的库缓存对象句柄的属性Name的值就是该SQL的SQL文本,属性Namespace的值就是常量“CRSR”,所以这里可以近似看作是只根据目标SQL的SQL文本来做哈希运算。
(2)然后在匹配的Hash Bucket的库缓存对象链表中查找匹配的Parent Cursor,当然,在查找匹配Parent Cursor的过程中肯定会比对目标SQL的SQL文本(因为不同的SQL文本计算出来的哈希值可能是相同的)。
(3)步骤2如果找到了匹配的Parent Cursor,则Oracle接下来就会遍历从属于该Parent Cursor的所有Child Cursor以查找匹配的Child Cursor。
(4)步骤2如果找不到了匹配的Parent Cursor,则也意味着此时没有可以共享的解析树和执行计划,Oracle就会从头开始解析上述目标SQL,新生成一个Parent Cursor和一个Child Cursor,并把它们挂在对应的Hash Bucket中。
(5)步骤3如果找到了匹配的Child Cursor,则Oracle就会把存储于该Child Cursor中的解析树和执行计划直接拿过来重用,而不用再从头开始解析。
(6)步骤3如果找不到匹配的Child Cursor,则意味着没有可以共享的解析树和执行计划,接下来Oracle也会从头开始解析上述目标SQL,新生成一个Child Cursor,并把这个Child Cursor挂在对应的Parent Cursor下。
1.2 硬解析
硬解析(Hard Parse)是指Oracle在执行目标SQL时,在库缓存中找不到可以重用的解析树和执行计划,而不得不从头开始解析目标SQL并生成相应的Parent Cursor和Child Cursor的过程。
硬解析实际上有两种类型,一种是在库缓存中找不到匹配的Parent Cursor,此时Oracle会从头开始解析目标SQL,新生成一个Parent Cursor和Child Cursor,并把它们挂在对应的Hash Bucket中;另一种是找到了匹配的Parent Cursor但未找到匹配的Child Cursor,此时Oracle也会从头开始解析该目标SQL,新生成一个Child Cursor,并把这个Child Cursor挂在对应的Parent Cursor下。
硬解析是非常不好的,它的危害性主要体现在如下这些方面:
硬解析可能会导致Shared Pool Latch的争用。无论是哪种类型的硬解析,都至少需要新生成一个Child Cursor,并把目标SQL的解析树和执行计划载入该Child Cursor里,然后把这个Child Cursor存储在库缓存中。这意味着Oracle必须在Shared Pool中分配出一块内存区域用于存储上述Child Cursor,而在Shared Pool中分配内存这个动作是要持有Shared Pool Latch的(Oracle数据库中的Latch的作用之一就是保护共享内存的分配),所以如果有一定数量的并发硬解析,可能会导致Shared Pool Latch争用,而且一旦发生大量的Shared Pool Latch争用,系统的性能和可扩展性会受到严重影响(常常表现为CPU的占用率居高不下,接近100%)。
硬解析可能会导致库缓存相关Latch(如Library Cache Latch)和Mutex的争用。无论是哪种类型的硬解析,都需要扫描相关的Hash Bucket中的库缓存对象句柄链表,而扫描库缓存对象句柄链表这个动作是要持有Library Cache Latch的(Oracle数据库中Latch的另外一个作用就是用于共享SGA内存结构的并发访问控制),所以如果有一定数量的并发硬解析,则可能会导致Library Cache Latch的争用。和Shared Pool Latch争用一样,一旦发生大量的Library Cache Latch的争用,系统的性能和可扩展性也会受到严重影响。从11gR1开始,Oracle用Mutex替换了库缓存相关Latch,所以在Oracle 11gR1及其后续的版本中,将不再存在库缓存相关Latch的急用,取而代之的是Mutex的争用(可以简单的将Mutex理解成一种轻量级的Latch,Mutex主要也是用于共享SGA内存结果的并发访问控制),Oracle也因此引入了一系列新的等待事件来描述这种Mutex的争用,比如:Cursor: pin S、Cursor: pin X、Cursor: pin S wait on X、Cursor:mutex S、Cursor:mutex X、Library cache:mutex X等。