Re: CBO tuning help needed

From: Charles Hooper <hooperc2000_at_yahoo.com>
Date: Fri, 25 Jan 2008 19:50:42 -0800 (PST)
Message-ID: <310f0abb-a80b-4548-b39c-e5b56d82a2ab@s13g2000prd.googlegroups.com>


On Jan 25, 4:32 pm, bhonaker <bhona..._at_gmail.com> wrote:
> Matthias: I found that there are many, many more histogram buckets on
> server B than on server A. More is better, right :-) ?
>
> David: Looking at DBMS_XPLAN output, it seems like the statistics are
> more complete on server B than on Server A.
>
> Charles: Block size was changed as this is the "new" warehouse server
> to be used for reporting (no OLTP) and we decided larger would be
> better for this type of system. Perhaps not. System statistics are
> not gathered on either system, looking into the impact of this.
> Please find DBMS_XPLAN info below. I do not understand why the
> recursion is occurring on server B. I would like to try the NOT
> EXISTS option, but a naysayer here says that the fact the same query
> performs sooooooooo much worse on server B is proof that there is
> something inherently wrong with the server. I am starting to think he
> is right...
>
> Here are the things I was able to try today.
> I tried gathering statistics on the entire schema using
> dbms_stats.gather_schema_stats (ownname=> 'OURSCHEMA', options=>
> 'GATHER', estimate_percent=> dbms_stats.auto_sample_size, method_opt=>
> 'for all columns size auto', cascade=> true, degree=> 5), but still
> the same plan is used.
> I tried exporting the statistics from server A and importing them on
> server B, no luck.
> Finally, I tried gathering maximum histogram info on server B using
> dbms_stats.gather_table_stats(ownname => 'OURSCHEMA', tabname=>
> 'OURTABLE', method_opt=> 'for all indexed columns size 254', cascade=>
> TRUE) for the tables that it seems to be having trouble making
> decisions about (TRANSACTIONS, REQUESTS, VISITS, BERTHS) and still no
> luck. Still banging away...
>
> Here is the DBMS_XPLAN output for each of the queries, sorry if the
> formatting gets wrecked. The problems seems to be that server B is
> not aware of this equality "REQUESTS"."VISIT_ID"="V"."ID" but instead
> is using this filter: "REQUESTS"."VISIT_ID"=:B1 - but there is no bind
> variable there in the query.
>
> Brian
>

(Snip)

The DBMS_XPLANs helped. After reviewing the explain plans, the performance problem is very likely NOT caused by a difference in the transformation of the NOT IN clause. There is an interesting difference in the explain plans. The fast executing plan uses the 9i and older "SORT GROUP BY", while the slow running query uses the 10g style "HASH GROUP BY" which does not perform an implicit sort during the GROUP BY. This may be an indication that there are differences in the parameters between the two databases. You might try checking the value of OPTIMIZER_FEATURES_ENABLE in each database, and also see if any parameters beginning with _ are set in the SPFILEs on each of the database servers.

NOT IN CLAUSE for the slow execution

|  26 |        NESTED LOOPS
|                              |    153 |      7 |     63 |00:00:00.08
|    4766 |      0 |      0 |       |        |          |         |
|  27 |         NESTED LOOPS
|                              |    153 |      7 |     63 |00:00:00.08
|    4577 |      0 |      0 |       |        |          |         |
|  28 |          NESTED LOOPS
|                              |    153 |      7 |     63 |00:00:00.07
|    4324 |      0 |      0 |       |        |          |         |
|  29 |           TABLE ACCESS BY INDEX ROWID |
REQUESTS                     |    153 |      7 |    778 |00:00:00.02
|    1208 |      0 |      0 |       |        |          |         |
|* 30 |            INDEX RANGE SCAN           |
REQUEST_VISIT_FK_I           |    153 |      7 |    778 |00:00:00.01
|     459 |      0 |      0 |       |        |          |         |
|* 31 |           TABLE ACCESS BY INDEX ROWID |
TRANSACTIONS                 |    778 |      1 |     63 |00:00:00.04
|    3116 |      0 |      0 |       |        |          |         |
|* 32 |            INDEX RANGE SCAN           |
TRA_REQ_FK_I                 |    778 |      1 |    793 |00:00:00.02
|    2336 |      0 |      0 |       |        |          |         |
|  33 |          TABLE ACCESS BY INDEX ROWID  |
TRANSACTION_ACCOUNT_XREF     |     63 |      1 |     63 |00:00:00.01
|     253 |      0 |      0 |       |        |          |         |
|* 34 |           INDEX RANGE SCAN            |
TAX_TRA_FK_I                 |     63 |      1 |     63 |00:00:00.01
|     189 |      0 |      0 |       |        |          |         |
|* 35 |         INDEX UNIQUE SCAN             |
ACCOUNT_PK                   |     63 |      1 |     63 |00:00:00.01
|     189 |      0 |      0 |       |        |          |         |

NOT IN CLAUSE fast execution, essentially the same
|  25 |            NESTED LOOPS
|                              |      7 |     63 |    4127 |      1
|      0 |00:00:00.03 |
|  26 |             NESTED LOOPS
|                              |      7 |     63 |    3938 |      1
|      0 |00:00:00.03 |
|  27 |              NESTED LOOPS
|                              |      7 |     63 |    3686 |      1
|      0 |00:00:00.03 |
|  28 |               TABLE ACCESS BY INDEX ROWID|
REQUESTS                     |      7 |    778 |    1193 |      1
|      0 |00:00:00.01 |
|* 29 |                INDEX RANGE SCAN          |
REQUEST_VISIT_FK_I           |      7 |    778 |     459 |      0
|      0 |00:00:00.01 |
|* 30 |               TABLE ACCESS BY INDEX ROWID|
TRANSACTIONS                 |      1 |     63 |    2493 |      0
|      0 |00:00:00.02 |
|* 31 |                INDEX RANGE SCAN          |
TRA_REQ_FK_I                 |      1 |    793 |    1714 |      0
|      0 |00:00:00.01 |
|  32 |              TABLE ACCESS BY INDEX ROWID |
TRANSACTION_ACCOUNT_XREF     |      1 |     63 |     252 |      0
|      0 |00:00:00.01 |
|* 33 |               INDEX RANGE SCAN           |
TAX_TRA_FK_I                 |      1 |     63 |     189 |      0
|      0 |00:00:00.01 |
|* 34 |             INDEX UNIQUE SCAN            |
ACCOUNT_PK                   |      1 |     63 |     189 |      0
|      0 |00:00:00.01 |

--

Now the interesting part.  The slow portion of the query is this:
    (SELECT DISTINCT
      REQUESTS1.visit_id COL1
    FROM
      idle2.transactions TRANSACTIONS1,
      idle2.requests REQUESTS1
    WHERE
      REQUESTS1.id = TRANSACTIONS1.request_id) TEMP0

In the slow running query, that portion of the plan looks like this:
|  22 |          HASH UNIQUE
|                              |      1 |   3661K|   8013K|00:03:17.32
|   87762 |    130K|  75701 |       |        |          |         |
|* 23 |           HASH JOIN
|                              |      1 |     26M|     28M|00:04:14.21
|   87762 |    109K|  54656 |   545M|    18M|   16M (1)|      868K|
|  24 |            INDEX FAST FULL SCAN       |
TRA_REQ_FK_I                 |      1 |     28M|     28M|00:02:49.08
|   32906 |      0 |      0 |       |        |          |         |
|  25 |            TABLE ACCESS FULL          |
REQUESTS                     |      1 |     26M|     26M|00:02:38.55
|   54856 |  54431 |      0 |       |        |          |         |

In the above, Oracle is performing a full tablescan on the REQUESTS
table in order to build a unique/distinct 26 million row list of
REQUESTS.VISIT_ID values.  Things are a bit different in the fast
query - Oracle does not build a distinct list of REQUESTS.VISIT_ID 26
milltion values.  Instead, Oracle drives into the TEMP0 view using
IDLE2.VISITS.ID column, allowing Oracle to perform an index lookup on
the REQUESTS table, thus retrieving just 715 rows, rather than having
to deal with a 26 million distinct list of VISIT_IDs.  This technique
is known as pushing predicates into views.  See the following for a
clear understanding:
  http://www.jlcomp.demon.co.uk/push_pred.html

You may be able to force Oracle 10.2.0.3 to push the predicate into
the view by using a hint directly after the word SELECT.  With the
hint, that section of the query might look like this (you might
instead try the hint   /*+ PUSH_PRED(TEMP0) ORDERED */   ):
  (SELECT /*+ PUSH_PRED(TEMP0) */
    B2.id as berth_id,
    round(sum(nvl(least(nvl(v.end_dt,sysdate),
    TO_DATE('01/01/2008 23:59:59', 'MM/DD/YYYY HH24:MI:SS')) -
greatest(v.start_dt, TO_DATE('01/01/2008 00:00:00', 'MM/DD/YYYY
HH24:MI:SS')), 0) * 24 * 60), 0) as used
  FROM
    idle2.berths B2,
    idle2.installations I2,
    idle2.visits v,
    (SELECT DISTINCT
      REQUESTS1.visit_id COL1
    FROM
      idle2.transactions TRANSACTIONS1,
      idle2.requests REQUESTS1
    WHERE
      REQUESTS1.id = TRANSACTIONS1.request_id) TEMP0
  WHERE
    B2.id = v.berth_id
    AND I2.id = B2.installation_id
    AND 24 = I2.id
    AND B2.parking_space_type_id not in (4, 21, 41)
    AND v.record_start_dt < new_time(TO_DATE('01/01/2008 23:59:59',
'MM/DD/YYYY HH24:MI:SS'), I2.time_zone, 'EST')
    AND nvl(v.record_end_dt, sysdate) > new_time(TO_DATE('01/01/2008
00:00:00', 'MM/DD/YYYY HH24:MI:SS'), I2.time_zone, 'EST')
    AND TEMP0.COL1 = v.id
    AND B2.installation_id = 24
    AND TEMP0.COL1 NOT IN (
...

Changing the value of OPTIMIZER_FEATURES_ENABLE on the new server so
that it matches the old server may be enough to allow Oracle to self-
correct the problem.

Charles Hooper
IT Manager/Oracle DBA
K&M Machine-Fabricating, Inc.
Received on Fri Jan 25 2008 - 21:50:42 CST

Original text of this message