基于ORACLE SQL优化书读之cursor(2)

2021/4/15 19:58:05

本文主要是介绍基于ORACLE SQL优化书读之cursor(2),对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

上篇文章主要介绍了关于cursor的一些实现和工作原理,以及关于父子cursor的存储方式等理论部分,接下来我们来进行一番实验来印证我们的理论。

如下为实验部分,在scott用户下进行查询emp表的数据:



SQL> select empno,ename from emp;

     EMPNO ENAME

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

      7369 SMITH

      7499 ALLEN

 ...

      7902 FORD

      7934 MILLER

已选择 14 行。

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                          1

SQL> select plan_hash_value,child_number from v$sql where sql_id='78bd3uh4a08av';

PLAN_HASH_VALUE CHILD_NUMBER

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

     3956160932            0



        注意原目标SQL在v$sqlarea中只有一条记录且version count为1,说明Oracle在执行SQL确实只产生一个parent cursor和child cursor,并且只产生了一个子游标号为0的child cursor。



SQL> select empno,ename from EMP;

     EMPNO ENAME

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

      7369 SMITH

      7499 ALLEN

 ...

      7900 JAMES

      7902 FORD

      7934 MILLER

已选择 14 行。

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                          1

select empno,ename from EMP                        53j2db788tnx9                          1

SQL> select plan_hash_value,child_number from v$sql where sql_id='53j2db788tnx9';

PLAN_HASH_VALUE CHILD_NUMBER

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

     3956160932            0




        之后把表emp改写成大写的EMP,发现又产生了一条游标记录,很明显是由于hash运算得到的哈希值去hash bucket中找匹配的parent cursor,由于hash运算对大小写的敏感性,导致hash bucket很有可能不是同一个,即便是同一个由于parent cursor中的name所存储的值也明显不同--即不同的SQL语句,所以肯定会产生一对新的parent cursor和child cursor。


然后我们再换另外一个用户test来尝试一下查询同一条sql语句,步骤如下:




SQL> conn test/test@orclp

已连接。

SQL> create table emp as select * from scott.emp;

表已创建。

SQL>

SQL>

SQL> select empno,ename from emp;

     EMPNO ENAME

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

      7369 SMITH

      7499 ALLEN

 ...

      7902 FORD

      7934 MILLER

已选择 14 行。

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

select empno,ename from EMP                        53j2db788tnx9                          1

SQL> select plan_hash_value,child_number from v$sql where sql_id='78bd3uh4a08av';

PLAN_HASH_VALUE CHILD_NUMBER

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

     3956160932            0

     3956160932            1



        上述实验表明,当我们使用另外一个用户来进行相同的查询时,Oracle会根据目标SQL文本的哈希值来找相应的hash bucket中的parent cursor,然后遍历其child cursor,但是此时发现child cursor中的解析数和执行计划不能被重用,原因是child cursor中的解析数和执行计划是针对Scott用户下的emp表,而不是针对test用户下的。也就是目标表不是同一张表,这也就意味着Oracle要针对test用户下的emp表再次从头做一次解析,并将结果存入新生成的child cursor中,再挂到parent cursor下,也就是说该SQL对应的parent cursor中会有两个child cursor。上述实验也验证了这一点,child_number值分别为0和1。


如下我们来归纳一下关于sql解析是如何在buffer cache中寻找cursor的过程:

watermark,size_16,text_QDUxQ1RP5Y2a5a6i,color_FFFFFF,t_100,g_se,x_10,y_10,shadow_90,type_ZmFuZ3poZW5naGVpdGk=

依次顺序执行如下步骤:

1)、根据目标SQL的SQL文本的hash 值去库缓存中找匹配的hash bucket,更准确的说是基于对应库缓存对象句柄属性name和namespace的值的;

2)、然后在匹配的hash bucket库缓存对象链表中查找匹配的parent cursor,当然,在查找匹配parent cursor的过程中肯定会比对目标的SQL的SQL文本(因为不同的SQL文本计算出来的hash 值可能相同)

3)、步骤2如果找到匹配的parent cursor,则Oracle接下来就会遍历从属于该parent cursor的所有child cursor查找匹配的child cursor。

4)、如果找不到匹配的parent cursor,就表明没有共享的解析数和执行计划,Oracle会从头解析SQL,新生成的parent cursor和一个child cursor,并把它们挂在对应的hash bucket中。

5)、步骤3如果找到匹配的child cursor,则Oracle会把存储于该child cursor中的解析数和执行计划直接拿过来重用。

6)、步骤3如果找不到匹配的child cursor,则表明没有可以共享的解析树和执行计划,Oracle会从头解析SQL。



这篇关于基于ORACLE SQL优化书读之cursor(2)的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程