> From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]]On Behalf Of Jonathan
> Lewis
> Sent: Saturday, March 16, 2002 8:58 AM
> To: Multiple recipients of list ORACLE-L
> Subject: Re: Fav. Urban Legend...
>
> and if Oracle can unnest the query, Oracle
> will unnest the query; for example, in the
> case of the SQL Gaja's used in paper, the
> subquery SQL will produce an execution
> plan matching the join SQL, with a line
>         VW_SQ_1
> as one of the 'tables' in the hash join.
>
> (Actually Oracle 8.1.7 will do this for
> some subquery operations without the
> hint - but so far none of the ones I've seen
> it in are correlated subqueries)
>

You can see something similar in 8.1.7 with correlated EXISTS if
always_semi_join = hash. 8.1.7 (and back through 7.3 I believe) can turn
EXISTS correlated sub-queries away from an NL approach into a HASH SEMI JOIN
(or merge semi join depending upon the parameter). The plan will not read
quite the same as the UNNEST hint approach:

SQL> alter session set always_semi_join = hash;

Session altered.
SQL> select *
  2  from code_master cm
  3  where exists (select null
  4                from code_detail cd
  5                where cm.code = cd.code)
  6  /

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=7089 Card=99900
Bytes=1498500)
   1    0   HASH JOIN (SEMI) (Cost=7089 Card=99900 Bytes=1498500)
   2    1     TABLE ACCESS (FULL) OF 'CODE_MASTER' (Cost=65 Card=100000
Bytes=1100000)
   3    1     INDEX (FAST FULL SCAN) OF 'CODE_DETAIL_PK' (UNIQUE) (Cost=214
Card=299600 Bytes=1198400)

SQL> alter session set always_semi_join = nested_loops;

Session altered.

With the UNNEST hint, I assume you were seeing something similar to the
following:

  1  select *
  2  from code_master cm
  3  where exists (select /*+ UNNEST */ null
  4                from code_detail cd
  5*               where cm.code = cd.code)
SQL> /

Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE (Cost=4070 Card=99900
Bytes=2397600)
   1    0   MERGE JOIN (SEMI) (Cost=4070 Card=99900 Bytes=2397600)
   2    1     TABLE ACCESS (BY INDEX ROWID) OF 'CODE_MASTER' (Cost=340
Card=100000 Bytes=1100000)
   3    2       INDEX (FULL SCAN) OF 'CODE_MASTER_PK' (UNIQUE) (Cost=188
Card=100000)
   4    1     SORT (UNIQUE) (Cost=3516 Card=299600 Bytes=3894800)
   5    4       VIEW OF 'VW_SQ_1' (Cost=214 Card=299600 Bytes=3894800)
   6    5         INDEX (FAST FULL SCAN) OF 'CODE_DETAIL_PK' (UNIQUE)
(Cost=214 Card=299600 Bytes=1198400)

And since you mentioned you hadn't seen the "unnesting" of correlated
sub-queries in 8.1.7, I assume you *have* seen it in 9i where the
always_semi_join and always_anti_join parameters became undocumented
parameters? Things start to get *really* interesting with the way the CBO
can transform and choose access paths for NOT IN / NOT EXISTS and IN /
EXISTS. For example, a NOT EXISTS can now (9i) be transformed into a HASH or
SEMI anti-join. Don't think that was possible in earlier versions (or at
least I couldn't make it happen)

This also has a downside in a way. For example, in 8i with always_anti_join
set to hash, if I *know* a correlated nested loops anti-join approach is
preferred, I can code a correlated NOT EXISTS and rely upon a nested loops
anti-join. On the other hand, if I *know* the criteria and data is such that
a hash anti-join is preferable for that query, I would code the query using
a NOT IN, and assuming the condition for a hash anti join are met, I would
get the hash anti join. I can't depend on that in 9i unless I set the
"_always_anti_join" parameter. Hopefully the CBO will make the right choices
and I will not have to set it or worry about it.

Larry G. Elkins


-- 
Please see the official ORACLE-L FAQ: http://www.orafaq.com
-- 
Author: Larry Elkins
  INET: [EMAIL PROTECTED]

Fat City Network Services    -- (858) 538-5051  FAX: (858) 538-5051
San Diego, California        -- Public Internet access / Mailing Lists
--------------------------------------------------------------------
To REMOVE yourself from this mailing list, send an E-Mail message
to: [EMAIL PROTECTED] (note EXACT spelling of 'ListGuru') and in
the message BODY, include a line containing: UNSUB ORACLE-L
(or the name of mailing list you want to be removed from).  You may
also send the HELP command for other information (like subscribing).

Reply via email to