Oracle里的Cursor(一)(2)

zx@MYDB>select empno,ename from EMP;
 
    EMPNO ENAME
---------- ------------------------------
      7369 SMITH
......省略部分输出
 
14 rows selected.

Oracle会根据目标SQL的SQL文本的哈希值去相应的Hash Bucket中找匹配的Parent Cursor,而哈希运算是对大小写敏感的,所以当我们执行上述改写后的目标SQL时,大写EMP所对应的Hash Bucket和小写emp所对应的Hash Bucket极有可能不是同一个Hash Bucket(即便是同一个Hash Bucket也没有关系,因为Oracle还会继续比对Parent Cursor所在的库缓存对象句柄的Name属性值,小写所对应的Parent Cursor的Name值为“select empno,ename from emp”,大写EMP对就的Parent Cursor的Name值为“select empno,ename from EMP”,两者显然不相等)。也就是说,小写emp所对应的Parent Cursor并不是大写EMP所要找的Parent Cursor,两者不能共享,所以此时Oracle肯定会新生成一对Parent Cursor和Child Cursor。

下面来验证一下:

zx@MYDB>select sql_text,sql_id,version_count from v$sqlarea where sql_text like 'select empno,ename%';
 
SQL_TEXT                      SQL_ID                  VERSION_COUNT
-------------------------------------------------- --------------------------------------- -------------
select empno,ename from emp            78bd3uh4a08av                    1
select empno,ename from EMP            53j2db788tnx9                    1
 
zx@MYDB>select plan_hash_value,child_number from v$sql where sql_id='53j2db788tnx9';
 
PLAN_HASH_VALUE CHILD_NUMBER
--------------- ------------
    3956160932      0

从上述结果可以看出,针对大写EMP所对应的目标SQL(大写EMP),Oracle确实新生成了一个Parent Cursor和一个Child Cursor。

现在构造一个同一个Parent Cursor下有不同Child Cursor的实例:

使用scott用户登录,再次执行小写emp所对应的目标SQL:

zx@MYDB>conn scott/tiger
Connected.
scott@MYDB>select empno,ename from emp;
 
    EMPNO ENAME
---------- ------------------------------
      7369 SMITH
......省略部分输出
 
14 rows selected.

Oracle根据目标SQL的SQL文本的哈希值去相应的Hash Bucket中找匹配的Parent Cursor,找到了匹配的Parent Cursor后还得遍历从属于该Parent Cursor的所有Child Cursor(因为可以被重用的解析权和执行计划都存储在Child Cursor中)。

对上述SQL(小写emp)而言,因为同样的SQL文本之前在ZX用户下已经执行过,在Library Cache中也已经生成了对应的Parent Cursor和Child Cursor,所以这里Oracle根据上述SQL的SQL文本的哈希值去Library Cache中找匹配的Parent Cursor时肯定时能找到匹配记录的。但接下来遍历从属于该Parent Cursor的所有Child Cursor时,Oracle会发现对应Child Cursor中存储的解析权和执行计划此时是不能被重用的,因为此时的Child Cursor里存储的解析树和执行计划针对的是ZX用户下的表EMP,面上述SQL针对的则是SCOTT用户下的同名表EMP,待查询的目标表根本就不是同一个表,解析权和执行计划当然不能共享了。这意味着Oracle还得针对上述SQL从头再做一次解析,并把解析后的解析树和执行计划存储在一个新生成的Child Cursor里,再把这个Child Cursor挂在上述Parent Cursor下(即把新生成的Child Cursor在库缓存对象句柄地址添加到上述Parent Cursor的Heap 0的Child table中)。也就是说一旦上述SQL执行完毕,该SQL所对应的Parent Cursor下就会有两个Child Cursor,一个Child Cursor中存储的是针对ZX用户下表EMP的解析树和执行计划,另外一个Child Cursor中存储的则是针对SCOTT用户下同名表EMP的解析树和执行计划。

使用如下语句验证:

scott@MYDB>select sql_text,sql_id,version_count from v$sqlarea where sql_text like 'select empno,ename%';
 
SQL_TEXT                      SQL_ID                  VERSION_COUNT
-------------------------------------------------- --------------------------------------- -------------
select empno,ename from emp            78bd3uh4a08av                    2
select empno,ename from EMP            53j2db788tnx9                    1

注意到上述SQL(小写emp)V$SQLAREA中的匹配记录的列VERSION_COUNT的值为2 ,说明Oracle在执行该SQL时确实产生了一个Parent Cursor和两个Child Cursor。

使用如下语句查询上述SQL所对应的Child Cursor的信息:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/215d6e3f4f048b048a0f7c8d04a6590f.html