- 数据库高效优化:架构、规范与SQL技巧
- 马立和 高振娇 韩锋
- 789字
- 2020-08-27 05:47:11
5.3 游标示例
下面我们来看一个关于游标的示例。
以SCOTT用户身份登录数据库:
conn scott/xxx select empno,ename from emp; //当一条SQL第一次被执行的时候,Oracle会同时产生一个Parent Cursor和一个Child Cursor 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 /* 目标SQL在V$SQLAREA中只有一条匹配记录,且这条记录的VERSION_COUNT的值为1(VERSION_COUNT表示某个Parent Cursor所拥有的所有Child Cursor的数量)。这说明了Oracle在执行这条SQL时确实只产生了一个Parent Cursor和一个Child Cursor */ select plan_hash_value,child_number from v$sql where sql_id='78bd3uh4a08av'; PLAN_HASH_VALUE CHILD_NUMBER --------------- ------------ 3956160932 0 /* 从V$SQL中查看所有Child Cursor的信息。根据SQL_ID查询V$SQL只有一条匹配记录,而且这条记录的CHILD_NUMBER的值为0(CHILD_NUMBER表示某个Child Cursor所对应的子游标号),说明Oracle在执行原目标SQL时确实只产生了一个编号为0的Child Cursor */ //以HF用户身份登录数据库 conn hf/hf create table emp as select * from scott.emp; select empno,ename from emp; //注意此时执行的SQL语句虽然与前面的相同,但其实是两个完全不同的语句 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 /* 在V$SQLAREA中发现匹配记录的VERSION_COUNTW为2,说明这个SQL语句有一个Parent Cursor和两个Child Cursor */ select plan_hash_value,child_number from v$sql where sql_id='78bd3uh4a08av'; PLAN_HASH_VALUE CHILD_NUMBER --------------- ------------ 3956160932 0 3956160932 1 //查看V$SQL,可以看到CHILD_NUMBER的值分别为0和1的两个Child Cursor
对于上面这个例子,第一条SQL在SCOTT用户下执行过,在Library Cache中已经生成了对应的Parent和Child Cursor。在HF用户执行相同文本的SQL时,Oracle根据上述SQL文本的哈希值去Library Cache中找匹配的Parent Cursor肯定能找到匹配记录。但接下来遍历从属于该Parent Cursor的所有Child Cursor时,Oracle会发现对应的Child Cursor中存储的解析树和执行计划是不能被重用的,因为此时的Child Cursor里存储的解析树和执行计划针对的是SCOTT用户下的表EMP,而后面执行的SQL对应的是HF用户下的表EMP。这里查询的不是同一个表,解析树和执行计划当然不能共享。这意味着Oracle还得针对上述SQL从头再做一次解析,并把解析后的解析树和执行计划存储在一个新生成的Child Cursor里,再把这个Child Cursor挂在上述Parent Cursor下(即把新生成的Child Cursor的库缓存对象句柄地址添加到上述Parent Cursor)。也就是说,一旦上述SQL执行完毕,该SQL所对应的Parent Cursor下就会有两个Child Cursor:一个Child Cursor中存储的是针对SCOTT用户下表EMP的解析树和执行计划;另外一个Child Cursor中存储的是针对HF用户下同名表EMP的解析树和执行计划。