Re: Unbelievable Outer Join

From: Charles Hooper <hooperc2000_at_yahoo.com>
Date: Wed, 12 Aug 2009 10:44:57 -0700 (PDT)
Message-ID: <f576ec4d-8e9e-4bb4-a6cb-0489f7ca6e32_at_k6g2000yqn.googlegroups.com>



On Aug 12, 12:10 pm, Jan <noreply...._at_gmail.com> wrote:
> Neither of the two tables is partitioned. The statistics are I believe
> accurate.
>
> The only way I can explain it is that it is a bug. But this is such a
> basic functionality that I can't believe it would not be fixed yet. It
> just seems too silly to be a bug.
>
> TT203_10100000001372631 is filtered during TABLE ACCESS FULL
> operation, but the way I undestand the plans is that 6798 rows will be
> left (moved into the next part which is the nested loop) after filter
> is applied. No filtering is applied during NESTED LOOPS OUTER
> operation, it's really just "6798 rows " left outer join "1 row" the
> way I understand it, which should result in  "6798 rows " not "1 row"
> as estimated.

This is typical behavior for a nested loop join. If you create a DBMS_XPLAN for the SQL statement showing actual execution statistics (with the STATISTICS_LEVEL set to ALL at the session level or a /*+ GATHER_PLAN_STATISTICS */ hint), you will see a couple additional columns in the plan - one of those columns is the STARTS column. If 6,798 is exactly the number of rows returned from the TT203_10100000001372631 table, you will see the number 6,798 in the starts column of the TABLE ACCESS BY INDEX ROWID | TI238_14935572 line in the plan.

For instance, a hash join for a query produces a DBMS_XPLAN output like this (broken up to avoid word wrap problems): Plan hash value: 2205292220


| Id  | Operation                     | Name   | Starts | E-Rows | A-
Rows |
|   0 | SELECT STATEMENT              |        |      1 |        |
10000 |
|*  1 |  FILTER                       |        |      1 |        |
10000 |
|*  2 |   HASH JOIN                   |        |      1 |     99 |
10000 |
|*  3 |    TABLE ACCESS FULL          | T3     |      1 |    100 |
10000 |
|   4 |    TABLE ACCESS BY INDEX ROWID| T4     |      1 |    100 |
10000 |
|*  5 |     INDEX RANGE SCAN          | IND_T4 |      1 |    100 |
10000 |
---------------------------------------------------------------------------

------------------------------------------------------------
| A-Time | Buffers | Reads | OMem | 1Mem | Used-Mem |
|00:00:00.01 |     532 |    355 |       |       |          |
|00:00:00.01 |     532 |    355 |       |       |          |
|00:00:00.01 |     532 |    355 |  1517K|  1517K| 1842K (0)|
|00:00:00.01 |     158 |    155 |       |       |          |
|00:00:00.01 |     374 |    200 |       |       |          |
|00:00:00.01 |     121 |     32 |       |       |          |
------------------------------------------------------------

Predicate Information (identified by operation id):


   1 - filter(:1<=:2)
   2 - access("T3"."C1"="T4"."C1")
   3 - filter(("T3"."C1"<=:2 AND "T3"."C1">=:1))
   5 - access("T4"."C1">=:1 AND "T4"."C1"<=:2)

The nested loop version of the plan looks like this:


| Id  | Operation                     | Name   | Starts | E-Rows | A-
Rows |
|   0 | SELECT STATEMENT              |        |      1 |        |
10000 |
|*  1 |  FILTER                       |        |      1 |        |
10000 |
|   2 |   NESTED LOOPS                |        |      1 |        |
10000 |
|   3 |    NESTED LOOPS               |        |      1 |     99 |
10000 |
|*  4 |     TABLE ACCESS FULL         | T3     |      1 |    100 |
10000 |
|*  5 |     INDEX RANGE SCAN          | IND_T4 |  10000 |      1 |
10000 |
|   6 |    TABLE ACCESS BY INDEX ROWID| T4     |  10000 |      1 |
10000 |
---------------------------------------------------------------------------

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

| A-Time | Buffers | Reads |
|00:00:00.06 |     876 |    355 |
|00:00:00.06 |     876 |    355 |
|00:00:00.06 |     876 |    355 |
|00:00:00.06 |     623 |    187 |
|00:00:00.06 |     257 |    155 |
|00:00:00.01 |     366 |     32 |
|00:00:00.01 |     253 |    168 |
--------------------------------

Predicate Information (identified by operation id):


   1 - filter(:1<=:2)
   4 - filter(("T3"."C1"<=:2 AND "T3"."C1">=:1))
   5 - access("T3"."C1"="T4"."C1")
       filter(("T4"."C1"<=:2 AND "T4"."C1">=:1))

Charles Hooper
IT Manager/Oracle DBA
K&M Machine-Fabricating, Inc. Received on Wed Aug 12 2009 - 12:44:57 CDT

Original text of this message