Oracle Scratchpad

December 30, 2011

FBI Bug

Filed under: Bugs,Execution plans,Function based indexes,Indexing,Oracle — Jonathan Lewis @ 5:47 pm BST Dec 30,2011

Here’s a funny little optimizer bug – though one that seems to have been fixed by at least 10.2.0.3. It showed up earlier on today in a thread on the OTN database forum. We’ll start (in 9.2.0.8) with a little table and two indexes – one normal, the other descending.

create table t1
as
with generator as (
	select	--+ materialize
		rownum id 
	from dual 
	connect by 
		level <= 10000
)
select
	rownum			id,
	lpad(rownum,10,'0')	small_vc,
	rpad('x',100)		padding
from
	generator	v1,
	generator	v2
where
	rownum <= 10000
;

-- collect stats

create index t1_id_asc  on t1(id) compute statistics;
create index t1_id_desc on t1(id desc) compute statistics;

You’ll notice that the two indexes are on the same column, even though one of them has (redundantly) declared the column to be treated in descending order. If I now execute the following query, noting the hint to use index t1_id_asc, would you expect the presence of index t1_id_desc to make any difference to the plan ?

select 
	/*+ index(t1 t1_id_asc) */
	* 
from 
	t1
where
	id between 1001 and 2000
;

Here are the plans, first with t1_id_desc in place:

---------------------------------------------------------------------------
| Id  | Operation                   |  Name       | Rows  | Bytes | Cost  |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |             |     3 |   342 |     5 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T1          |     3 |   342 |     5 |
|*  2 |   INDEX RANGE SCAN          | T1_ID_ASC   |     3 |       |     4 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("T1"."ID">=1001 AND "T1"."ID"<=2000)
       filter(SYS_OP_DESCEND("T1"."ID")<=HEXTORAW('3DF4FDFF')  AND
              SYS_OP_DESCEND("T1"."ID")>=HEXTORAW('3DEAFF') )

Now after dropping index t1_id_desc

---------------------------------------------------------------------------
| Id  | Operation                   |  Name       | Rows  | Bytes | Cost  |
---------------------------------------------------------------------------
|   0 | SELECT STATEMENT            |             |  1001 |   111K|    22 |
|   1 |  TABLE ACCESS BY INDEX ROWID| T1          |  1001 |   111K|    22 |
|*  2 |   INDEX RANGE SCAN          | T1_ID_ASC   |  1001 |       |     4 |
---------------------------------------------------------------------------

Predicate Information (identified by operation id):
---------------------------------------------------
   2 - access("T1"."ID">=1001 AND "T1"."ID"<=2000)

The shape of the two plans hasn’t changed, of course, they’ve both obeyed my hint. Notice, however, the changes in the Predicate Information and the estimated cardinalities. With index t1_id_desc in place, the optimizer has found the definition of the hidden column representing the “id desc” and used it to generate some new predicates, introducing some extra factors into the calculation of selectivity.

In the case of the OTN query, the initial inputs were bind variables – which meant the new predicates looked like:

       filter(SYS_OP_DESCEND("D"."CREATEDAT")<=SYS_OP_DESCEND(:Z) AND
              SYS_OP_DESCEND("D"."CREATEDAT")>=SYS_OP_DESCEND(:Z))

In this version of Oracle this resulted in the predicates being treated as “guesses on an index range scan” – which resulted in the optimizer ignoring the appropriate index (until hinted) even though the cost calculation gave a lower cost.

Update 31 Dec 2011: It’s just occurred to me that this is another example of a case where you can drop an index that isn’t being used and find that execution plans can change as a side effect. (Conversely, you create an index that shouldn’t change any execution plans – and some plans change, even though they don’t use the index.) Luckily, as I pointed out above, this demo came from 9.2.0.8, and the behaviour has been fixed by 10.2.0.3 (and possible earlier).

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

The Rubric Theme. Blog at WordPress.com.

Follow

Get every new post delivered to your Inbox.

Join 3,530 other followers