Skip to Main Content
  • Questions
  • Does oracle support bi-direction(either ascending or descending) index?

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Danielle.

Asked: September 14, 2001 - 12:59 pm UTC

Last updated: February 07, 2006 - 6:22 am UTC

Version: 8.1.7

Viewed 1000+ times

You Asked

I understand we can specify asc or desc when creating index. And wonder if it is possible to specify it in some way like BIDIR, with which oracle can identify the best direction (asc or desc) based on the query.
Is there such a feature in oracle 8.1.7?

Thanks for your time,

Danielle

and Tom said...

Oracle will use indexes in ascending and desc mode as needed. It can and will read indexes "front to back" or "back to front".

the DESC option on the create index is applied at the column level so that an index:

( a, b desc, c )

will sort by A ascending, B descending, C ascending -- something that cannot be done just by reading the index backwards and forwards....

Rating

  (15 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

Indexes

jm, September 14, 2001 - 5:23 pm UTC

But why will we use such an index like ( a , b desc , c) .
Can you explain this with some example.

Tom Kyte
September 14, 2001 - 5:28 pm UTC

create index on emp ( job, sal DESC, ename );

That will sort the data by job from low to high (A-Z) and salary HIGH to low and within the same salaries by ename.

That would show you the highest paid people FIRST by job for example.

artistic way to do it

Mikito Harakiri, September 14, 2001 - 5:38 pm UTC

&lttitle, MINUS(sal), ...&gt should also do the trick

need further clarification

Danielle, September 14, 2001 - 5:55 pm UTC

Tom,
Thanks for the quick feedback.
I was thinking about a parameter that can allow both directions (asc and desc).
For example, if having such a parameter BIDIR (like ASC/DESC). then I create the index sal_idx on salary column wtih BIDIR. When a query does "selects min(sal) from emp", ascending index is used. If a query does "selects max(sal) from emp", descending indext is used for faster search.

I don't think oracle supports/has this, but want to get your confirmation.

Thanks,

Tom Kyte
September 14, 2001 - 6:03 pm UTC

We already do this. We read indexes backwards and forwards all of the time.

This happens naturally all of the time.

ASC/DESC with single column index

Kamal Kishore, May 09, 2003 - 9:18 pm UTC

Hi Tom,
Is it correct to assume (from the discussion above) that specifying ASC or DESC when creating an index on one single column is of no significance as Oracle will be able to do this kind of reading forward/backward automatically, with or without ASC/DESC specified (with equal efficiency).

Then, Does it matter (change the execution plan or otherwise) if this ASC/DESC was specified (compared to not specifying when creating the index)?


Tom Kyte
May 10, 2003 - 7:31 am UTC

the discussion above points out that just reading the index backwards and forwards is not the same as using ASC/DESC on each column -- when you mix ASC and DESC up (when some columns are ASC and some are DESC)


so no, they are not equivalent.

Optimizer does not recognize desc index

Alanoly Andrews, December 17, 2004 - 5:30 pm UTC

I have cases in which the Oracle optimizer does not recognize a multi-field index in which one(possibly more) of the fields is declared as DESC. See the following example (from Oracle 8.1.7):

 
SQL> create table testtable(col1 integer, col2 char(30), col3 char(10));
 
Table created.
 
SQL> alter table testtable add primary key(col1, col2);
 
Table altered.
 
SQL> create index ind1 on testtable(col2, col3);
 
Index created.
 
SQL> set autotrace traceonly explain;
SQL> select * from testtable order by col2, col3;
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TESTTABLE'
   2    1     INDEX (FULL SCAN) OF 'IND1' (NON-UNIQUE)
 
 
 
SQL> create index ind2 on testtable(col2 desc, col3);
 
Index created.
 
SQL> select * from testtable order by col2 desc, col3;
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   SORT (ORDER BY)
   2    1     TABLE ACCESS (FULL) OF 'TESTTABLE'
 
 
 
SQL>

In this last query, I expect to see the index ind2 being used. Instead the Optimizer goes for a table access. Is there an explanation for this? Without a "hint", how can the Optimizer persuaded to use ind2, as it should, for this query?

Thanks. 

Tom Kyte
December 18, 2004 - 8:43 am UTC

you are using the brain dead RBO which does not see the DESC and if you flipped to the CBO, you have an empty table....

but the CBO would see it when it makes sense to see it.



ops$tkyte@ORA9IR2> select * from testtable order by col2 desc, col3;
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   SORT (ORDER BY)
   2    1     TABLE ACCESS (FULL) OF 'TESTTABLE'
 
 
 
ops$tkyte@ORA9IR2> select /*+ FIRST_ROWS */ * from testtable order by col2 desc, col3;
 
Execution Plan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=HINT: FIRST_ROWS (Cost=826 Card=82 Bytes=4674)
   1    0   TABLE ACCESS (BY INDEX ROWID) OF 'TESTTABLE' (Cost=826 Card=82 Bytes=4674)
   2    1     INDEX (FULL SCAN) OF 'IND2' (NON-UNIQUE) (Cost=26 Card=82)
 

Index block split

Keval Shah, March 14, 2005 - 1:32 am UTC

Does this ordering value matter at the time of splitting index data block?

Consider my key value is populated by decrementing sequence and when the index leaf block is full and DESC is specified then it will make 90:10 split otherwise 50:50 split.

Index stats

Keval Shah, March 14, 2005 - 2:57 am UTC

my above conclusion is based on following small test run

drop table t
create table t ( n1 number, n2 number )
create index t_n1 on t ( n1 )
create index t_n2 on t ( n2 desc )
insert into t select rownum, rownum from dual connect by 1=1 and rownum < 1500


after analyzing index t_n2 is having 6 leaf blocks where as t_n1 is having only 3 leaf blocks.

Tom Kyte
March 14, 2005 - 8:03 am UTC

but that doesn't do what you said above.

"Consider my key value is populated by decrementing sequence"

Decision based on Insert and not on Select

Keval Shah, March 15, 2005 - 8:05 am UTC

While inserting records in ascending order the ascending index made 90:10 split where as the descending index made 50:50 split. So decision to create ASC / DESC index should be based on in which order the data will be populated rather than in which order they will be queired.

Pls. clarify if I am wrong.

Thanks.

Tom Kyte
March 15, 2005 - 8:45 am UTC

the decision for asc/desc is made based on HOW YOU USE the index more than anything else.

In the special case of a single column index, it is ok to use this concept, but in general, you would not take an index on (a,b,c) and decide to make b DESC due to this -- you would have to see how you use the index.

If you take a snippet of code such as:


void show_leaf( char * msg )
{
exec sql begin declare section;
varchar name[50];
int value;
exec sql end declare section;

exec sql whenever sqlerror do die();
printf( "%s\n", msg );
exec sql declare c cursor for
select a.name, b.value
from v$statname a, v$mystat b
where a.statistic# = b.statistic#
and lower(a.name) like 'leaf%';


exec sql open c;
exec sql whenever notfound do break;
for( ;; )
{
exec sql fetch c into :name, :value;
printf( "%30.*s %d\n", name.len, name.arr, value );
}
exec sql whenever notfound continue;
exec sql close c;
}

void process(void)
{
exec sql begin declare section;
int i;
exec sql end declare section;

exec sql whenever sqlerror continue;
exec sql drop table t1;
exec sql drop table t2;

exec sql whenever sqlerror do die();
exec sql create table t1 ( x int );
exec sql create index t1_idx on t1(x);

exec sql create table t2 ( x int );
exec sql create index t2_idx on t2(x desc);

show_leaf( "before ascending insert" );
for( i = 0; i < 100000; i++ )
{
exec sql insert into t1(x) values (:i);
}
show_leaf( "after ascending, before descending" );
for( i = 100000; i > -1; i-- )
{
exec sql insert into t2(x) values (:i);
}
show_leaf( "after descending" );
}


you can see the 90/10 splits happening for both indexes:


[tkyte@xtkyte-pc t]$ ./t
connecting
connected
before ascending insert
leaf node splits 0
leaf node 90-10 splits 0
after ascending, before descending
leaf node splits 198
leaf node 90-10 splits 198
after descending
leaf node splits 409
leaf node 90-10 splits 409
[tkyte@xtkyte-pc t]$


if you remove the DESC from the second create index, it would look more like this:

[tkyte@xtkyte-pc t]$ ./t
connecting
connected
before ascending insert
leaf node splits 0
leaf node 90-10 splits 0
after ascending, before descending
leaf node splits 198
leaf node 90-10 splits 198
after descending
leaf node splits 600
leaf node 90-10 splits 198


but again, this would not be my only deciding factor.

result interpreting

Keval Shah, March 15, 2005 - 10:09 am UTC

So this shows that when we have a descending index and values are populated in decrementing order then it made 211 block split [ all 90:10 ] but if descending values populated in ascending index then it made 402 block split and none of them is 90:10.

just interpreting result of your code.

Tom Kyte
March 15, 2005 - 10:15 am UTC

yes...

HOW YOU USE

A reader, April 20, 2005 - 5:19 pm UTC

<quote>
the decision for asc/desc is made based on HOW YOU USE the index more than anything else.
<quote>

can you pls. elaborate more on "HOW YOU USE index"

thanks.

Tom Kyte
April 20, 2005 - 9:19 pm UTC

select * from t where .... order by X desc, Y asc, Z desc;

maybe I want an index on (x DESC,y ASC, z DESC) for that.



A reader, April 21, 2005 - 4:31 am UTC

how will index on (x DESC,y ASC, z DESC) be better than index on (x, y, z) when leaf nodes are stored in doubly linked list?

Tom Kyte
April 21, 2005 - 6:22 am UTC

what does a doubly linked list have to do with it?

If you need to retrieve the data sorted by

X desc
Y asc
Z desc

and the index is on (x desc, y asc, z desc)

then the plan could use the index to read the data sorted in that order.

asc and desc in select

Reader, October 11, 2005 - 4:37 pm UTC

Hi Tom,
I have a table A with one column and 4 rows as an example shown below.

create table a (id number)

insert into a id values (1)
insert into a id values (2)
insert into a id values (3)
insert into a id values (4)

commit;

How can I achieve the following results

Result should look like

Id1 Id2
1 4
2 3
3 2
4 1

Please advise?????

Tom Kyte
October 12, 2005 - 6:42 am UTC

ops$tkyte@ORA10GR1> select t1.id, t2.id
  2    from ( select id, row_number() over (order by id) rn from a ) t1,
  3         ( select id, row_number() over (order by id desc) rn from a ) t2
  4   where t1.rn = t2.rn;
 
        ID         ID
---------- ----------
         1          4
         2          3
         3          2
         4          1
 

Not going to be great with tons of data obviously. 

leaf node 90-10 splits

A reader, October 17, 2005 - 2:20 pm UTC

Hi

I am trying to find information about the difference between

leaf node 90-10 splits and leaf node splits

leaf node splits is easy to understand, index leaf splits when no more data can fit in the leaf block

I cant find anything about except this comment by J. Lewis:

A new index entry that sorts above all other keys
will not cause a normal index leaf split. Instead
Oracle adds a new leaf block and inserts this single
entry into it. This is recorded as a 90/10 split.
The mechanism has existed for years, and is the
mechanism that allows indexes on sequence-based
columns to run at 100% packing.

I dont quite understand here, is he saying that this is simply adding a leaf block to a index branch? For example if I have a sequence (primary key) which increases from 1 to 1000000 will all my leaf node splits be 90/10 since leaf blocks are always added?

May be this is a bit stupid question, is there anyway to create an index with specific leaves to an empty table so when there wont be index splits when inserts are being carried out?

I am a bit confused because of the 90/10 term.

Thank you

Tom Kyte
October 17, 2005 - 2:48 pm UTC

if you are indexing a field that is always "growing" (eg: a sequence populated column, a date populated with sysdate for example), then the index only grows on the "right hand side"

when we recognize that - that the index is "righ handed", only increasing values are being added - when the right hand block fills up - we split it 90/10 - 90% of the data goes "left" and 10% goes "right".

That way, the index is about 90% full all of the time, nicely packed (assuming just inserts in this trivial case)


If we did a 60/40 (consider it a 50/50 split for ease of thinking) split during this operation - the index would be about 60% used instead.

if you do not insert "always growing" values - the index will do a normal split putting about half of the data to the left and the right - because data is inserted all over the place - not in order, this makes sense.

sort order

A reader, February 06, 2006 - 10:36 am UTC

hi tom,

concerning your example:

select t1.id, t2.id
from ( select id, row_number() over (order by id) rn from a ) t1,
( select id, row_number() over (order by id desc) rn from a ) t2
where t1.rn = t2.rn
/

is it guaranteed that we will ever get this result in sort order of t1 or will we have to give an additional "order by t1.id" clause to get this guaranteed?

Tom Kyte
February 07, 2006 - 1:00 am UTC

there is no assurance that this data is sorted by anything.

unless there is an order by, I was just doing the "join"

sort order

A reader, February 07, 2006 - 6:20 am UTC

hi tom,

thanks for your answer. i based my question on the fact that there are already two "order by" clauses in the inline views! the inner result sets are "window" sorted and t1 is used as driving set in the following.

TEST @ adm1 SQL>select t1.id, t2.id
  2  from ( select id, row_number() over (order by id) rn from a      ) t1,
  3       ( select id, row_number() over (order by id desc) rn from a ) t2
  4  where t1.rn = t2.rn
  5  /

Abgelaufen: 00:00:00.80

Ausführungsplan
----------------------------------------------------------
   0      SELECT STATEMENT Optimizer=CHOOSE
   1    0   MERGE JOIN
   2    1     SORT (JOIN)
   3    2       VIEW
   4    3         WINDOW (SORT)
   5    4           TABLE ACCESS (FULL) OF 'A'
   6    1     SORT (JOIN)
   7    6       VIEW
   8    7         WINDOW (SORT)
   9    8           TABLE ACCESS (FULL) OF 'A'


it seems that it is very unlikely that the data will come in another order. doesn't it? 

Tom Kyte
February 07, 2006 - 6:22 am UTC

no, it does not seem very unlikely...

it is purely by accident.

you want data sorted, use order by on the query. the order by on the analytics are "accidental", incidental, non-assured side effects.

(you see the sorts are in different orders? one asc, one desc....