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.
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
<title, MINUS(sal), ...> 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,
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)?
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.
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.
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.
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.
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.
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?
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?????
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
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?
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?
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....