ITPub博客

首页 > Linux操作系统 > Linux操作系统 > precompute_subquery hint的使用三

precompute_subquery hint的使用三

原创 Linux操作系统 作者:lucy_lxy 时间:2011-09-21 14:02:59 0 删除 编辑

接下来,让我们增加更多的行数到表T2来看看子光标们能增长到多大:

SQL> delete t2;

5555 rows deleted.

SQL> insert into t2 select rownum from dual connect by level <= 99999;

99999 rows created.

SQL> select a from t1 where a in (select /*+ PRECOMPUTE_SUBQUERY */b from t2);

         A

----------

         1

         2

         3

         4

         5

         6

         7

         8

         9

9 rows selected.

SQL> @hash

HASH_VALUE SQL_ID        CHILD_NUMBER

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

4073976606 5phajvmtd7wsy            2

SQL> @curheaps 4073976606 2

  KGLNAHSH KGLHDPAR     CHILD# KGLHDADR KGLOBHD0    SIZE0    SIZE1    SIZE2    SIZE3    SIZE4    SIZE5 KGLOBHD6    SIZE6    SIZE7

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

4073976606 3175A618          2 3343C208 2FD9768C     3392        0        0        0        0        0 312B45D8   925236        0

HEAP  CLASS    ALLOC_COMMENT         BYTES     CHUNKS

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

HEAP0 perm     permanent memor        2500          4

HEAP0 free     free memory             412          2

HEAP0 freeabl  kgltbtab                228          3

HEAP  CLASS    ALLOC_COMMENT         BYTES     CHUNKS

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

HEAP6 freeabl  optdef: qcopCre      720288      10000

HEAP6 freeabl  strdef_buf : kk      196476      10001

HEAP6 freeabl  kctdef : kkqucu        1460          5

HEAP6 freeabl  kctdef : qcdlgo         876          3

HEAP6 freeabl  ctxdef:kksLoadC         488          1

HEAP6 free     free memory             456          1

[..snip..删减]

HEAP6 freeabl  opixfalo:froaty          16          1

53 rows selected.

看,似乎所允许的过滤条件的最大数目是10000(这个测试是在11.1.0.7 on Linux上做的)。并且不是所有的内存结构都有10000+ 桶(chunks) 填充的。似乎是在解析过程中,Oracle认识到有太多的过滤条件存放在内存中了,因此它抽离出来,从precompute_subquery函数中返回了失败。这就导致precompute_subquery Hint被忽略了,生成的执行计划仅仅好似没有该hint 存在一样:

----------------------------------------------------------------------------昂

| Id  | Operation           | Name     | E-Rows |  OMem |  1Mem | Used-Mem |

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

|   0 | SELECT STATEMENT    |          |        |       |       |          |

|*  1 |  HASH JOIN SEMI     |          |      1 |  1066K|  1066K| 1084K (0)|

|   2 |   TABLE ACCESS FULL | T1       |      9 |       |       |          |

|   3 |   VIEW              | VW_NSO_1 |      9 |       |       |          |

|   4 |    TABLE ACCESS FULL| T2       |      9 |       |       |          |

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

Predicate Information (identified by operation id):

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

   1 - access("A"="B")

这应该是很明显的, precompute_subquery hint 没有被真正忽略掉。优化器确实增加了它,但是在它认识到所有的条件和规则不是都满足外,它抽离出来(这应该很好的示例说明了这个事实,有效的hints永远不会被忽略—他们会被处理,但是有时其他的输入条件使得优化器终止使用它)。注意这个hint 是一种特殊的情况,它恰好击中了一种内部硬编码限制,基于真实处理的行数,而不是一个基于成本的判断。

另外一个直接的问题应该是,当top-level 查询被重新执行时(当它已经被缓存在library cache中的时候),Oracle 总是触发对表T2的递归子查询.如果不是这样,我们可能得终止使用缓存在 heap6中的错误的过滤条件,如果T2的内容发生变化的话。

答案是,不论何时Oracle 在不同的上下文中运行一个查询的部分内容,它都将会把top-level 查询打上标记,其后续的执行将不能共享光标规则,并最终总是导致一个硬解析发生。从我的hash.sql脚本输出内容里面,就是你在上面所看到的,child_number在每次执行里面都是增加的。

让我们用nonshared.sql脚本(其仅仅查询v$sql_shared_cursor视图,但是格式化输出得更好一些)检查一下,没有共享光标的原因。这个脚本要使用SQL_ID作为参数:

SQL> @nonshared 5phajvmtd7wsy

SQL_ID                        : 5phajvmtd7wsy

ADDRESS                       : 3175A618

CHILD_ADDRESS                 : 3175B56C

CHILD_NUMBER                  : 0

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

SQL_ID                        : 5phajvmtd7wsy

ADDRESS                       : 3175A618

CHILD_ADDRESS                 : 2FD2D6DC

CHILD_NUMBER                  : 1

CURSOR_PARTS_MISMATCH         : Y

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

SQL_ID                        : 5phajvmtd7wsy

ADDRESS                       : 3175A618

CHILD_ADDRESS                 : 3343C208

CHILD_NUMBER                  : 2

CURSOR_PARTS_MISMATCH         : Y

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

PL/SQL procedure successfully completed.

Oracle documentation 关于CURSOR_PARTS_MISMATCH说明如下:

“Cursor was compiled with subexecution (cursor parts were executed)”

光标被编译用子执行(被执行的光标部分)

所以,Oracle现在可以从主查询中摘取子查询的文本,分别执行它们,然后将执行完的结果返回给主查询作为“硬编码”的过滤值。

似乎这个特性仅仅被用于Oracle OLAP选项,对于常规的SQL不自动地使用。原因是在Oracle里面,没有足够有效的“半连接”(semijoin)操作可应用到OLAP 数据上,因此,这种优化(在我的每个简短的测试中,subquery precomputing的执行效率实际上都比一个哈希半连接要差)。

最后,这个hint 是没有文档说明的(可能一般认为是对OLAP而言的) ,所以请不要试图使用它来优化你的查询!:)

 

 

作者的sql脚本我没下载。

但是得出的结论是不要轻易使用该hint,我的应用版本也比较低,放弃了,记录在此!

 

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

请登录后发表评论 登录
全部评论

注册时间:2010-09-27

  • 博文量
    124
  • 访问量
    391599