Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> c.d.o.server -> Strange Cost Based Optimizer Decision Making

Strange Cost Based Optimizer Decision Making

From: Jimbo1 <nightfanguk_at_yahoo.co.uk>
Date: 19 Dec 2005 07:17:40 -0800
Message-ID: <1135005460.049605.253440@o13g2000cwo.googlegroups.com>


Hello there,

I'm experiencing some 'strangeness' from the CBO when running a query in an Oracle 8i (8.1.7) database.

Before I describe the problem, I'm just going to take some time out to request that all the Oracle Support-like users of this forum who will instantly say "You must upgrade to 10g R2 to solve this!", no disrespect intended, but please don't bother if that is all you have to contribute. We're fully aware that we need to upgrade, but a greater priority at this point in time is fixing the system within the bounds of 8i. This is a business decision, not a technical decision, and that's the way it's going to be played.

Anyway, with that out of the way, let me describe my problem (in the hope that Jonathan Lewis takes an active interest ;o)).

I have one very large range-partitioned table (on month), containing in the region of 672 million rows in total. There is a NON-UNIQUE composite index on two columns in this table; LINK_ID and TIME_STAMP. When I run the following query against it, I get a perfect execution plan for what I need:

QUERY 1 - HUGE_TABLE MAX(time_stamp) query results



SQL> SELECT /*+ CHOOSE */
  2 MAX(time_stamp)
  3 FROM huge_table;

MAX(TIME_



19-DEC-05 Elapsed: 00:00:02.81

Execution Plan


   0 SELECT STATEMENT Optimizer=HINT: CHOOSE (Cost=4 Card=1 Bytes=8)

   1 0 SORT (AGGREGATE)

   2    1     PARTITION RANGE (ALL)
   3    2       INDEX (FULL SCAN (MIN/MAX)) OF
'HUGE_TABLE_PK'(NON-UNIQUE) (Cost=4 Card=315382450 Bytes=2523059600)

With only a 2.81 second execution time, this query does what it needs to do very quickly for such a large table. Note the "INDEX (FULL SCAN (MIN/MAX))" of the non-unique 2-column composite index on this table.

Now, I have another table that's not quite so large, containing over 65 million rows. The statistics on this table are 100% completely up to date. Once again, this table is range-partitioned on month. However, this time, there is a UNIQUE composite index present on two columns: SECTION_ID and TIME_STAMP.

I run an identical SELECT clause to the last query against this table. However, this is the execution plan I get:

QUERY 2 - LARGE_TABLE MAX(time_stamp) query results



SQL> SELECT /*+ CHOOSE */
  2 MAX(time_stamp)
  3 FROM large_table;

MAX(TIME_



30-SEP-05 Elapsed: 00:04:261.22

Execution Plan


   0 SELECT STATEMENT Optimizer=HINT: CHOOSE (Cost=34394 Card=1 Bytes=8)

   1 0 SORT (AGGREGATE)

   2    1     PARTITION RANGE (ALL)
   3    2       TABLE ACCESS (FULL) OF 'LARGE_TABLE' (Cost=34394
Card=65623008 Bytes=524984064)

Right, I'm no longer getting a (MIN/MAX) full index scan. Instead I'm getting a full table scan of each partition, and the query is taking over four minutes to run for a table that is ten times smaller than the previous one. Now, the strange thing is, as I've already said, is all the stats are fully up to date for LARGE_TABLE. This includes the index stats.

The really strange thing is that the stats for HUGE_TABLE and its associated index are more than 6 months out of date, yet the execution plan for my query on this table is perfect, i.e. I get the (MIN/MAX) full index scan.

All indexes concerned are local (partitioned) indexes. The only structural difference between the two is that the index on HUGE_TABLE is non-unique, and the index on LARGE_TABLE is unique. Why would the unique index not be picked up for a (MIN/MAX) full index scan if the stats are all present and up-to-date?

I know some people reading this will be saying, "He must have missed something; it must be the stats.". For these people, the stats for both tables and indexes are displayed below.

COMPARISON BETWEEN GLOBAL TABLE STATS BETWEEN "HUGE_TABLE" AND
"LARGE_TABLE"



SQL> select table_name,
  2         num_rows,
  3         last_analyzed

  4 from user_tables
  5 where table_name IN ('HUGE_TABLE', 'LARGE_TABLE');

TABLE_NAME NUM_ROWS LAST_ANAL

--------------- --------- ---------
LARGE_TABLE      65623008 16-DEC-05
HUGE_TABLE      315382450 17-MAY-05


COMPARISON BETWEEN GLOBAL INDEX STATS BETWEEN "HUGE_TABLE" AND
"LARGE_TABLE"


SQL> SELECT index_name,
  2         table_name,
  3         uniqueness,
  4         num_rows,
  5         last_analyzed,
  6         partitioned
  7     FROM user_indexes

  8 WHERE index_name IN ('HUGE_TABLE_PK', 'LARGE_TABLE_PK');
INDEX_NAME        TABLE_NAME                     UNIQUENES   NUM_ROWS
LAST_ANAL PARTITIONED
----------------- ------------------------------ --------- ----------
--------- -----------
LARGE_TABLE_PK    LARGE_TABLE                    UNIQUE      65623008
16-DEC-05 YES
HUGE_TABLE_PK     HUGE_TABLE                     NONUNIQUE  316185229
17-MAY-05 YES COMPARISON OF TABLE PARTITION STATS BETWEEN "HUGE_TABLE" AND
"LARGE_TABLE"

TABLE_NAME PARTITION_NAME NUM_ROWS LAST_ANAL

--------------------- ---------------- ---------- ---------
LARGE_TABLE           JAN_2005            6880338 16-DEC-05
LARGE_TABLE           FEB_2005            6175009 16-DEC-05
LARGE_TABLE           MAR_2005            6853129 16-DEC-05
LARGE_TABLE           APR_2005            6546195 16-DEC-05
LARGE_TABLE           MAY_2005            6753167 16-DEC-05
LARGE_TABLE           JUN_2005            6568995 16-DEC-05
LARGE_TABLE           JUL_2005            6909996 16-DEC-05
LARGE_TABLE           AUG_2005            6915392 16-DEC-05
LARGE_TABLE           SEP_2005            5361894 16-DEC-05
LARGE_TABLE           OCT_2005                  0 16-DEC-05
LARGE_TABLE           NOV_2005                  0 16-DEC-05
LARGE_TABLE           DEC_2005                  0 16-DEC-05
LARGE_TABLE           END_TIME                  0 16-DEC-05
LARGE_TABLE           DEC_2004            6658893 16-DEC-05


TABLE_NAME            PARTITION_NAME     NUM_ROWS LAST_ANAL
--------------------- ---------------- ---------- ---------
HUGE_TABLE            JAN_2005           60081900 17-MAY-05
HUGE_TABLE            FEB_2005           51027010 17-MAY-05
HUGE_TABLE            END_TIME
HUGE_TABLE            DEC_2005
HUGE_TABLE            DEC_2004           58722850 17-MAY-05
HUGE_TABLE            NOV_2005
HUGE_TABLE            JUN_2005
HUGE_TABLE            JUL_2005
HUGE_TABLE            APR_2005           56117100 17-MAY-05
HUGE_TABLE            MAY_2005           30367650 17-MAY-05
HUGE_TABLE            AUG_2005
HUGE_TABLE            SEP_2005
HUGE_TABLE            OCT_2005
HUGE_TABLE            MAR_2005           59288350 17-MAY-05


COMPARISON OF INDEX PARTITION STATS BETWEEN "HUGE_TABLE_PK" AND
"LARGE_TABLE_PK"



SQL> SELECT index_name,
  2         partition_name,
  3         num_rows,
  4         last_analyzed

  5 FROM user_ind_partitions
  6 WHERE index_name = 'LARGE_TABLE_PK';

INDEX_NAME PARTITION_NAME NUM_ROWS LAST_ANAL

--------------------- --------------- ---------- ---------
LARGE_TABLE_PK        JAN_2005           6880338 16-DEC-05
LARGE_TABLE_PK        FEB_2005           6175009 16-DEC-05
LARGE_TABLE_PK        MAR_2005           6853129 16-DEC-05
LARGE_TABLE_PK        APR_2005           6546195 16-DEC-05
LARGE_TABLE_PK        MAY_2005           6753167 16-DEC-05
LARGE_TABLE_PK        JUN_2005           6568995 16-DEC-05
LARGE_TABLE_PK        JUL_2005           6909996 16-DEC-05
LARGE_TABLE_PK        AUG_2005           6915392 16-DEC-05
LARGE_TABLE_PK        SEP_2005           5361894 16-DEC-05
LARGE_TABLE_PK        OCT_2005                 0 16-DEC-05
LARGE_TABLE_PK        NOV_2005                 0 16-DEC-05
LARGE_TABLE_PK        DEC_2005                 0 16-DEC-05
LARGE_TABLE_PK        END_TIME                 0 16-DEC-05
LARGE_TABLE_PK        DEC_2004           6658893 16-DEC-05


SQL> SELECT index_name,
  2         partition_name,
  3         num_rows,
  4         last_analyzed

  5 FROM user_ind_partitions
  6 WHERE index_name = 'HUGE_TABLE_PK';

INDEX_NAME PARTITION_NAME NUM_ROWS LAST_ANAL

--------------------- --------------- ---------- ---------
HUGE_TABLE_PK         MAY_2005        30618961.3 17-MAY-05
HUGE_TABLE_PK         JUN_2005
HUGE_TABLE_PK         MAR_2005          59092640 17-MAY-05
HUGE_TABLE_PK         FEB_2005        51459094.7 17-MAY-05
HUGE_TABLE_PK         APR_2005        56270813.7 17-MAY-05
HUGE_TABLE_PK         JAN_2005        59800077.5 17-MAY-05
HUGE_TABLE_PK         DEC_2005
HUGE_TABLE_PK         END_TIME
HUGE_TABLE_PK         NOV_2005
HUGE_TABLE_PK         DEC_2004        58943641.5 17-MAY-05
HUGE_TABLE_PK         JUL_2005
HUGE_TABLE_PK         AUG_2005
HUGE_TABLE_PK         SEP_2005
HUGE_TABLE_PK         OCT_2005


If the situation was the reverse, I would immediately blame the lack of stats on HUGE_TABLE and its index. However, LARGE_TABLE and its index have up-to-date stats, yet the CBO is choosing to full table scan the partitions of this table, rather than (MIN/MAX) full index scan its unique local index.

For a table and index with massively out of date stats, the CBO is choosing a (MIN/MAX) full index scan for the desired query.

Does anybody reading this feel they can shed any light on why the CBO is behaving in this way, and what I might have missed?

Thanks in advance.

James Received on Mon Dec 19 2005 - 09:17:40 CST

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US