about subquery unnest/push pred
本站文章除注明转载外,均为本站原创: 转载自love wife love life —Roger的Oracle/MySQL/PostgreSQL数据恢复博客
本文链接地址: about subquery unnest/push pred
落落的sql优化班级确实牛叉,我也试听了1次,学不到不少东西,如果大家有兴趣,可以加他的试听QQ群:179221471
今天抽空做了下关于子查询和谓词推入的实验,我这里通过vm 10gR2环境来模拟展示。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 | SQL> conn roger/roger Connected. SQL> create table t1 as select * from dba_objects where object_id < 3000; Table created. SQL> create table t2 as select * from dba_objects; Table created. SQL> create index idx_id1_t2 on t2(object_id,owner); Index created. SQL> create index idx_id1_t1 on t1(object_id); Index created. SQL> set autot traceonly exp SQL> analyze table t1 compute statistics for all indexed columns; Table analyzed. SQL>  analyze table t2 compute statistics for all indexed columns; Table analyzed. SQL> set autot traceonly SQL> select object_id from t1 where exists (   2  select 1 from t2 where t1.object_id=t2.object_id-10); 2911 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 2210107937 ------------------------------------------------------------------------------------ | Id  | Operation             | Name       | Rows  | Bytes | Cost (%CPU)| Time     | ------------------------------------------------------------------------------------ |   0 | SELECT STATEMENT      |            |     1 |    17 |   203   (1)| 00:00:03 | |*  1 |  HASH JOIN SEMI       |            |     1 |    17 |   203   (1)| 00:00:03 | |   2 |   INDEX FAST FULL SCAN| IDX_ID1_T1 |  2950 | 38350 |     5   (0)| 00:00:01 | |   3 |   TABLE ACCESS FULL   | T2         | 49910 |   194K|   198   (1)| 00:00:03 | ------------------------------------------------------------------------------------ Predicate Information (identified by operation id): ---------------------------------------------------    1 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID"-10) Note -----    - dynamic sampling used for this statement Statistics ----------------------------------------------------------         713  recursive calls           0  db block gets        1136  consistent gets         553  physical reads           0  redo size       40114  bytes sent via SQL*Net to client        2534  bytes received via SQL*Net from client         196  SQL*Net roundtrips to/from client          21  sorts (memory)           0  sorts (disk)        2911  rows processed | 
上面的例子中,oracle自动将子查询进行了展开,下面我们使用no_unnest hint来不让oracle在这里进行子查询展开,就通过
嵌套在子查询里面,那么这样比如就会走fiter了,如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | SQL>  alter system flush shared_pool; System altered. SQL> select object_id   2    from t1   3   where exists (select /*+no_unnest*/   4           1   5            from t2   6           where t1.object_id = t2.object_id - 10); 2911 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 895956251 --------------------------------------------------------------------------- | Id  | Operation          | Name | Rows  | Bytes | Cost (%CPU)| Time     | --------------------------------------------------------------------------- |   0 | SELECT STATEMENT   |      |     1 |     3 |  4442   (1)| 00:00:54 | |*  1 |  FILTER            |      |       |       |            |          | |   2 |   TABLE ACCESS FULL| T1   |  2950 |  8850 |    13   (0)| 00:00:01 | |*  3 |   TABLE ACCESS FULL| T2   |   499 |  1996 |     3   (0)| 00:00:01 | --------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    1 - filter( EXISTS (SELECT /*+ NO_UNNEST */ 0 FROM "T2" "T2" WHERE               "T2"."OBJECT_ID"-10=:B1))    3 - filter("T2"."OBJECT_ID"-10=:B1) | 
在10g中,oracle默认就会进行子查询的展开,这是通过一个隐含参数来进行控制的,如下:
SQL> show parameter unnest
NAME                                 TYPE        VALUE
———————————— ———– ——————————
_distinct_view_unnesting             boolean     FALSE
_unnest_subquery                     boolean     TRUE
SQL>
我们可以发现,_unnest_subquery 参数默认是true.
当子查询返回的结果集如果很小的话,这个时候其实是可以走fiter的,换句话讲,这个时候就可以不进行子查询的展开。
那么什么情况下存在子查询的情况,oracle不会进行子查询的展开呢 ?
—包含rownum
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | SQL> select object_id   2    from t1   3   where exists (select 1 from t2 where t1.object_id = t2.object_id-10 and rownum < 20); 2911 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 4265634519 ---------------------------------------------------------------------------- | Id  | Operation           | Name | Rows  | Bytes | Cost (%CPU)| Time     | ---------------------------------------------------------------------------- |   0 | SELECT STATEMENT    |      |     1 |     3 |  4442   (1)| 00:00:54 | |*  1 |  FILTER             |      |       |       |            |          | |   2 |   TABLE ACCESS FULL | T1   |  2950 |  8850 |    13   (0)| 00:00:01 | |*  3 |   COUNT STOPKEY     |      |       |       |            |          | |*  4 |    TABLE ACCESS FULL| T2   |   499 |  1996 |     3   (0)| 00:00:01 | ---------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    1 - filter( EXISTS (SELECT 0 FROM "T2" "T2" WHERE ROWNUM<20 AND               "T2"."OBJECT_ID"-10=:B1))    3 - filter(ROWNUM<20)    4 - filter("T2"."OBJECT_ID"-10=:B1) | 
—包含cube、rollup 等函数
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | SQL> select object_id   2    from t1   3   where exists (select 1,sum(object_id) from t2 where t1.object_id = t2.object_id-10 group by rollup(t2.object_id)); 2911 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 3739889183 ------------------------------------------------------------------------------ | Id  | Operation             | Name | Rows  | Bytes | Cost (%CPU)| Time     | ------------------------------------------------------------------------------ |   0 | SELECT STATEMENT      |      |     1 |     3 |   293K  (1)| 00:58:38 | |*  1 |  FILTER               |      |       |       |            |          | |   2 |   TABLE ACCESS FULL   | T1   |  2950 |  8850 |    13   (0)| 00:00:01 | |   3 |   SORT GROUP BY ROLLUP|      |   499 |  1996 |   199   (2)| 00:00:03 | |*  4 |    TABLE ACCESS FULL  | T2   |   499 |  1996 |   198   (1)| 00:00:03 | ------------------------------------------------------------------------------ Predicate Information (identified by operation id): ---------------------------------------------------    1 - filter( EXISTS (SELECT 0 FROM "T2" "T2" WHERE               "T2"."OBJECT_ID"-10=:B1 GROUP BY  ROLLUP ("T2"."OBJECT_ID")))    4 - filter("T2"."OBJECT_ID"-10=:B1) | 
—包含union all、union、INTERSECT、 MINUS等
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | SQL> select object_id   2    from t1   3   where exists (select 1 from t2 where t1.object_id = t2.object_id-10  union all   4    select object_id from t2 where object_id < 500); 2950 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 2568596142 ---------------------------------------------------------------------------------- | Id  | Operation           | Name       | Rows  | Bytes | Cost (%CPU)| Time     | ---------------------------------------------------------------------------------- |   0 | SELECT STATEMENT    |            |     1 |     4 |   296K  (1)| 00:59:14 | |*  1 |  FILTER             |            |       |       |            |          | |   2 |   TABLE ACCESS FULL | T1         |  2950 | 11800 |    13   (0)| 00:00:01 | |   3 |   UNION-ALL         |            |       |       |            |          | |*  4 |    TABLE ACCESS FULL| T2         |   511 |  2555 |   198   (1)| 00:00:03 | |*  5 |    INDEX RANGE SCAN | IDX_ID1_T2 |   417 |  2085 |     3   (0)| 00:00:01 | ---------------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    1 - filter( EXISTS ( (SELECT 1 FROM "T2" "T2" WHERE               "T2"."OBJECT_ID"-10=:B1) UNION ALL  (SELECT "OBJECT_ID" FROM "T2" "T2"               WHERE "OBJECT_ID"<500)))    4 - filter("T2"."OBJECT_ID"-10=:B1)    5 - access("OBJECT_ID"<500) | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | SQL> select object_id   2    from t1   3   where exists (select 1 from t2 where t1.object_id = t2.object_id-10  union   4    select object_id from t2 where object_id < 500); 2950 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 583540251 ----------------------------------------------------------------------------------- | Id  | Operation            | Name       | Rows  | Bytes | Cost (%CPU)| Time     | ----------------------------------------------------------------------------------- |   0 | SELECT STATEMENT     |            |     1 |     4 |   299K  (2)| 00:59:49 | |*  1 |  FILTER              |            |       |       |            |          | |   2 |   TABLE ACCESS FULL  | T1         |  2950 | 11800 |    13   (0)| 00:00:01 | |   3 |   SORT UNIQUE        |            |   928 |  4640 |   203   (3)| 00:00:03 | |   4 |    UNION-ALL         |            |       |       |            |          | |*  5 |     TABLE ACCESS FULL| T2         |   511 |  2555 |   198   (1)| 00:00:03 | |*  6 |     INDEX RANGE SCAN | IDX_ID1_T2 |   417 |  2085 |     3   (0)| 00:00:01 | ----------------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    1 - filter( EXISTS ( (SELECT 1 FROM "T2" "T2" WHERE               "T2"."OBJECT_ID"-10=:B1)UNION (SELECT "OBJECT_ID" FROM "T2" "T2" WHERE               "OBJECT_ID"<500)))    5 - filter("T2"."OBJECT_ID"-10=:B1)    6 - access("OBJECT_ID"<500) | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | SQL> select object_id   2      from t1   3      where exists (select 1 from t2 where t1.object_id = t2.object_id-10  MINUS   4      select object_id from t2 where object_id < 500); 2911 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 1945478487 ----------------------------------------------------------------------------------- | Id  | Operation            | Name       | Rows  | Bytes | Cost (%CPU)| Time     | ----------------------------------------------------------------------------------- |   0 | SELECT STATEMENT     |            |     1 |     4 |   299K  (2)| 00:59:49 | |*  1 |  FILTER              |            |       |       |            |          | |   2 |   TABLE ACCESS FULL  | T1         |  2950 | 11800 |    13   (0)| 00:00:01 | |   3 |   MINUS              |            |       |       |            |          | |   4 |    SORT UNIQUE NOSORT|            |   511 |  2555 |   199   (2)| 00:00:03 | |*  5 |     TABLE ACCESS FULL| T2         |   511 |  2555 |   198   (1)| 00:00:03 | |   6 |    SORT UNIQUE NOSORT|            |   417 |  2085 |     4  (25)| 00:00:01 | |*  7 |     INDEX RANGE SCAN | IDX_ID1_T2 |   417 |  2085 |     3   (0)| 00:00:01 | ----------------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    1 - filter( EXISTS ( (SELECT 1 FROM "T2" "T2" WHERE               "T2"."OBJECT_ID"-10=:B1)MINUS (SELECT "OBJECT_ID" FROM "T2" "T2" WHERE               "OBJECT_ID"<500)))    5 - filter("T2"."OBJECT_ID"-10=:B1)    7 - access("OBJECT_ID"<500) | 
—包含start with…connect by
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | SQL> select object_id   2    from t1   3   where exists (select 1   4            from t2   5           start with owner='SYS'   6           connect by object_id >100 and object_id < 200); 2950 rows selected. Execution Plan ---------------------------------------------------------- Plan hash value: 1433996639 -------------------------------------------------------------------------------------------- | Id  | Operation                     | Name       | Rows  | Bytes | Cost (%CPU)| Time     | -------------------------------------------------------------------------------------------- |   0 | SELECT STATEMENT              |            |  2950 | 11800 |    15   (0)| 00:00:01 | |*  1 |  FILTER                       |            |       |       |            |          | |   2 |   TABLE ACCESS FULL           | T1         |  2950 | 11800 |    13   (0)| 00:00:01 | |*  3 |   CONNECT BY WITHOUT FILTERING|            |       |       |            |          | |*  4 |    INDEX FAST FULL SCAN       | IDX_ID1_T2 | 23084 |   247K|    43   (0)| 00:00:01 | |   5 |    TABLE ACCESS FULL          | T2         | 51088 |   249K|   198   (1)| 00:00:03 | -------------------------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    1 - filter( EXISTS (SELECT 0 FROM "T2" "T2" CONNECT BY "OBJECT_ID">100 AND               "OBJECT_ID"<200 START WITH "OWNER"='SYS'))    3 - filter("OBJECT_ID">100 AND "OBJECT_ID"<200)    4 - filter("OWNER"='SYS') | 
我们再来看下试图合并,首先我们创建几个测试表。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | SQL> create table t3 as select * from dba_objects where object_id < 10000; Table created. SQL> analyze table t3 compute statistics; Table analyzed. SQL> create or replace view t_view   2  as   3  select t1.* from t1,t2   4  where   5  t1.object_id=t2.object_id; View created. SQL> SQL> set autot traceonly  exp SQL> select t3.object_name   2    from t3, t_view   3   where t3.object_name = t_view.object_name(+)   4     and t3.object_id = 888; Execution Plan ---------------------------------------------------------- Plan hash value: 1962414821 -------------------------------------------------------------------------------------- | Id  | Operation               | Name       | Rows  | Bytes | Cost (%CPU)| Time     | -------------------------------------------------------------------------------------- |   0 | SELECT STATEMENT        |            |     1 |    86 |    95   (3)| 00:00:02 | |*  1 |  HASH JOIN OUTER        |            |     1 |    86 |    95   (3)| 00:00:02 | |*  2 |   TABLE ACCESS FULL     | T3         |     1 |    20 |    37   (0)| 00:00:01 | |   3 |   VIEW                  | T_VIEW     |  2950 |   190K|    57   (2)| 00:00:01 | |*  4 |    HASH JOIN            |            |  2950 | 76700 |    57   (2)| 00:00:01 | |   5 |     TABLE ACCESS FULL   | T1         |  2950 | 61950 |    13   (0)| 00:00:01 | |   6 |     INDEX FAST FULL SCAN| IDX_ID1_T2 | 51088 |   249K|    43   (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    1 - access("T3"."OBJECT_NAME"="T_VIEW"."OBJECT_NAME"(+))    2 - filter("T3"."OBJECT_ID"=888)    4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID") SQL> | 
从上面可以看到t3的条件进行了fiter操作,并没有推进到view里面去,下面我们使用push_pred hint进行强制推进下。
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | SQL> alter system flush shared_pool; System altered. SQL> SQL> select /*+push_pred(t_view)*/ t3.object_name   2    from t3, t_view   3   where t3.object_name = t_view.object_name(+)   4     and t3.object_id = 888; Execution Plan ---------------------------------------------------------- Plan hash value: 3014823912 -------------------------------------------------------------------------------------- | Id  | Operation               | Name       | Rows  | Bytes | Cost (%CPU)| Time     | -------------------------------------------------------------------------------------- |   0 | SELECT STATEMENT        |            |     1 |    22 |    51   (0)| 00:00:01 | |   1 |  NESTED LOOPS OUTER     |            |     1 |    22 |    51   (0)| 00:00:01 | |*  2 |   TABLE ACCESS FULL     | T3         |     1 |    20 |    37   (0)| 00:00:01 | |   3 |   VIEW PUSHED PREDICATE | T_VIEW     |     1 |     2 |    14   (0)| 00:00:01 | |   4 |    NESTED LOOPS         |            |     1 |    26 |    14   (0)| 00:00:01 | |*  5 |     TABLE ACCESS FULL   | T1         |     1 |    21 |    13   (0)| 00:00:01 | |*  6 |     INDEX RANGE SCAN    | IDX_ID1_T2 |     1 |     5 |     1   (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    2 - filter("T3"."OBJECT_ID"=888)    5 - filter("T1"."OBJECT_NAME"="T3"."OBJECT_NAME")    6 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID") | 
| 1 | 实际上这里如果进行merge的话,也可以实现类似的效果,如下: | 
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 | <pre class="brush:sql">SQL> select /*+merge(t_view)*/t3.object_name   2    from t3, t_view   3   where  t3.object_name=t_view.object_name   4     and t3.object_id = 888; Execution Plan ---------------------------------------------------------- Plan hash value: 2983785075 ---------------------------------------------------------------------------------- | Id  | Operation           | Name       | Rows  | Bytes | Cost (%CPU)| Time     | ---------------------------------------------------------------------------------- |   0 | SELECT STATEMENT    |            |     1 |    46 |    52   (2)| 00:00:01 | |   1 |  NESTED LOOPS       |            |     1 |    46 |    52   (2)| 00:00:01 | |*  2 |   HASH JOIN         |            |     1 |    41 |    51   (2)| 00:00:01 | |*  3 |    TABLE ACCESS FULL| T3         |     1 |    20 |    37   (0)| 00:00:01 | |   4 |    TABLE ACCESS FULL| T1         |  2950 | 61950 |    13   (0)| 00:00:01 | |*  5 |   INDEX RANGE SCAN  | IDX_ID1_T2 |     1 |     5 |     1   (0)| 00:00:01 | ---------------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    2 - access("T3"."OBJECT_NAME"="T1"."OBJECT_NAME")    3 - filter("T3"."OBJECT_ID"=888)    5 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID") SQL> select /*+no_merge(t_view)*/t3.object_name   2    from t3, t_view   3   where  t3.object_name=t_view.object_name   4     and t3.object_id = 888; Execution Plan ---------------------------------------------------------- Plan hash value: 2958396757 -------------------------------------------------------------------------------------- | Id  | Operation               | Name       | Rows  | Bytes | Cost (%CPU)| Time     | -------------------------------------------------------------------------------------- |   0 | SELECT STATEMENT        |            |     1 |    86 |    95   (3)| 00:00:02 | |*  1 |  HASH JOIN              |            |     1 |    86 |    95   (3)| 00:00:02 | |*  2 |   TABLE ACCESS FULL     | T3         |     1 |    20 |    37   (0)| 00:00:01 | |   3 |   VIEW                  | T_VIEW     |  2950 |   190K|    57   (2)| 00:00:01 | |*  4 |    HASH JOIN            |            |  2950 | 76700 |    57   (2)| 00:00:01 | |   5 |     TABLE ACCESS FULL   | T1         |  2950 | 61950 |    13   (0)| 00:00:01 | |   6 |     INDEX FAST FULL SCAN| IDX_ID1_T2 | 51088 |   249K|    43   (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    1 - access("T3"."OBJECT_NAME"="T_VIEW"."OBJECT_NAME")    2 - filter("T3"."OBJECT_ID"=888)    4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID") | 
当sql查询中出现view,实际上使用merge/no_merge和push_pred,no_push_pred我感觉有些类似。
如下一段关于merge 和 push_pred的描述:
Merge / no_merge: if you use a complex view (e.g. aggregate view, or join view) in your query, should you rewrite
the query to merge the tables in the view into a single from clause with all the other tables (merge), or should
you evaluate the view to produce a “standalone” result set and then join the result set to the remaining tables (no_merge).
Push_pred / no_push_pred: If you have a non-mergeable view (possible because of a no_merge hint) in your query, how
should you operate the join from other tables; should you create one large view result and join it once (no_push_pred)
or should you push the join predicate down into the view definition and recreate the view result set for every driving
row from another table (push_pred).
merge 就是把view展开,那么你查看执行计划时就看不到view acces patch的信息了,no_merge则相反。
所以push_pred(谓词推入)就是是说将谓词条件推入到view中。
由于要发现push pred操作,必须保证试图不能被merge,所以通常在实验观察时会同时使用no_merge hint.
细心一点我们还能发现,针对谓词推入的操作,其外部操作只能是nest loop。
到最后我们可以简单的总结下,针对如下情况,子查询是不能展开的:
1.子查询存在 ROWNUM
2.子查询存在 CUBE,ROLLUP
3.子查询存在 UNION, UNION ALL,INTERSECT、 MINUS
4.子查询存在 START WITH ,CONNECT BY 字句
通常我发现针对右外连接的情况下,oracle优化器默认也不会进行view merge操作,如下:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | SQL> select t3.object_name from t3,t_view where t3.object_name=t_view.object_name(+)   2  and t3.object_id=888; Execution Plan ---------------------------------------------------------- Plan hash value: 1962414821 -------------------------------------------------------------------------------------- | Id  | Operation               | Name       | Rows  | Bytes | Cost (%CPU)| Time     | -------------------------------------------------------------------------------------- |   0 | SELECT STATEMENT        |            |     1 |    88 |    95   (3)| 00:00:02 | |*  1 |  HASH JOIN OUTER        |            |     1 |    88 |    95   (3)| 00:00:02 | |*  2 |   TABLE ACCESS FULL     | T3         |     1 |    22 |    37   (0)| 00:00:01 | |   3 |   VIEW                  | T_VIEW     |  2950 |   190K|    57   (2)| 00:00:01 | |*  4 |    HASH JOIN            |            |  2950 | 76700 |    57   (2)| 00:00:01 | |   5 |     TABLE ACCESS FULL   | T1         |  2950 | 61950 |    13   (0)| 00:00:01 | |   6 |     INDEX FAST FULL SCAN| IDX_ID1_T2 | 51088 |   249K|    43   (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    1 - access("T3"."OBJECT_NAME"="T_VIEW"."OBJECT_NAME"(+))    2 - filter("T3"."OBJECT_ID"=888)    4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID") | 
事实上针对这样的情况,强制使用merge hint也不起作用,如果不存在右外连接的情况下,是可以自动进行merge的:
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | SQL> select /*+merge(t_view)*/t3.object_name from t3,t_view where t3.object_name=t_view.object_name(+)   2  and t3.object_id=888; Execution Plan ---------------------------------------------------------- Plan hash value: 1962414821 -------------------------------------------------------------------------------------- | Id  | Operation               | Name       | Rows  | Bytes | Cost (%CPU)| Time     | -------------------------------------------------------------------------------------- |   0 | SELECT STATEMENT        |            |     1 |    88 |    95   (3)| 00:00:02 | |*  1 |  HASH JOIN OUTER        |            |     1 |    88 |    95   (3)| 00:00:02 | |*  2 |   TABLE ACCESS FULL     | T3         |     1 |    22 |    37   (0)| 00:00:01 | |   3 |   VIEW                  | T_VIEW     |  2950 |   190K|    57   (2)| 00:00:01 | |*  4 |    HASH JOIN            |            |  2950 | 76700 |    57   (2)| 00:00:01 | |   5 |     TABLE ACCESS FULL   | T1         |  2950 | 61950 |    13   (0)| 00:00:01 | |   6 |     INDEX FAST FULL SCAN| IDX_ID1_T2 | 51088 |   249K|    43   (0)| 00:00:01 | -------------------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    1 - access("T3"."OBJECT_NAME"="T_VIEW"."OBJECT_NAME"(+))    2 - filter("T3"."OBJECT_ID"=888)    4 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID") SQL> alter system flush shared_pool; System altered. SQL>  select t3.object_name from t3,t_view where t3.object_name=t_view.object_name   2  and t3.object_id=888; Execution Plan ---------------------------------------------------------- Plan hash value: 2983785075 ---------------------------------------------------------------------------------- | Id  | Operation           | Name       | Rows  | Bytes | Cost (%CPU)| Time     | ---------------------------------------------------------------------------------- |   0 | SELECT STATEMENT    |            |     1 |    48 |    52   (2)| 00:00:01 | |   1 |  NESTED LOOPS       |            |     1 |    48 |    52   (2)| 00:00:01 | |*  2 |   HASH JOIN         |            |     1 |    43 |    51   (2)| 00:00:01 | |*  3 |    TABLE ACCESS FULL| T3         |     1 |    22 |    37   (0)| 00:00:01 | |   4 |    TABLE ACCESS FULL| T1         |  2950 | 61950 |    13   (0)| 00:00:01 | |*  5 |   INDEX RANGE SCAN  | IDX_ID1_T2 |     1 |     5 |     1   (0)| 00:00:01 | ---------------------------------------------------------------------------------- Predicate Information (identified by operation id): ---------------------------------------------------    2 - access("T3"."OBJECT_NAME"="T1"."OBJECT_NAME")    3 - filter("T3"."OBJECT_ID"=888)    5 - access("T1"."OBJECT_ID"="T2"."OBJECT_ID") | 
该默认行为是oracle通过一个参数来进行控制的,如下:
SQL> show parameter view
NAME                                 TYPE        VALUE
———————————— ———– ——————————
_complex_view_merging                boolean     TRUE
_distinct_view_unnesting             boolean     FALSE
_partition_view_enabled              boolean     TRUE
_project_view_columns                boolean     TRUE
_push_join_union_view                boolean     TRUE
_push_join_union_view2               boolean     TRUE
_simple_view_merging                 boolean     TRUE
optimizer_secure_view_merging        boolean     TRUE
在10gR2版本中 _simple_view_merging 参数默认是true。



One Response to “about subquery unnest/push pred”
不错 写的很好
Leave a Reply
You must be logged in to post a comment.