Skip to Main Content

Breadcrumb

Question and Answer

Tom Kyte

Thanks for the question, Sergey.

Asked: March 07, 2003 - 1:10 pm UTC

Last updated: March 19, 2006 - 2:15 pm UTC

Version: 8.1.7.4

Viewed 10K+ times! This question is

You Asked

Hi, Tom!

I have unique index created as create unique index... instead of as consequence constraint unique.
Then I do it UNUSABLE,

I carry out
alter session set skip_unusable_indexes=true

Also I try to insert a line into the table, I receive
ORA-01502: index 'IDX_OBJ' or partition of such index is in unusable state

If to do the same actions, on a usual index the line is inserted without problems.

The parameter skip_unusable_indexes is not distributed on unique index? What else there are restrictions?
How it is possible to disconnect unique index (created as create unique index...) not deleting it?

For example:

/* Oracle: Release 8.1.7.4 */

create table t as
select object_id from all_objects where rownum < 9
/
-- attempt 1 ****
create unique index idx_obj on t (object_id)
/
alter index idx_obj unusable
/
insert into t values (-1)
/
ORA-01502: index 'IDX_OBJ' or partition of such index is in unusable state

alter session set skip_unusable_indexes=true
/
insert into t values (-1)
/
ORA-01502: index 'IDX_OBJ' or partition of such index is in unusable state
-- end attempt 1 ****
drop index idx_obj
/
alter session set skip_unusable_indexes=false
/
-- attempt 2 ****
create index idx_obj on t (object_id)
/
alter index idx_obj unusable
/
insert into t values (-1)
/
ORA-01502: index 'IDX_OBJ' or partition of such index is in unusable state

alter session set skip_unusable_indexes=true
/
insert into t values (-1)
/
1 row created.
-- end attempt 2 ****

Regards
Sergey from Kharkov, Ukraine


and Tom said...



</code> http://docs.oracle.com/cd/B10501_01/server.920/a96540/statements_22a.htm#2182515 <code>

<quote>
If an index is used to enforce a UNIQUE constraint on a table, then allowing
insert and update operations on the table might violate the constraint.
Therefore, this setting does not disable error reporting for unusable indexes
that are unique.
</quote>


you'll either have to have it

o usuable

or

o drop and recreate it.

Rating

  (24 ratings)

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

Comments

Sergey

Sergey, March 11, 2003 - 2:22 am UTC

Thank you very much

Incorrect results?

Kamal Kishore, June 29, 2003 - 4:33 pm UTC

Hi Tom,
In your book expert one-on-one Oracle page 651, you said:
<quote>
this works in Oracle 8.1.5 and later versions; prior to that, SELECT statement wold still try to use the UNUSABLE index
</quote>

Does this mean that prior to 8.1.5, we had a chance of not getting an error and the query will generate incorrect results, without our finding out?
Thanks,


Tom Kyte
June 29, 2003 - 6:27 pm UTC

no, it was that skip_unusable_indexes would not skip the indexes, the statement would fail with an error.

Lingering questions...

Craig, January 09, 2004 - 10:11 am UTC

How would you recommend we proceed in a data warehouse environment, where we have big nightly loads? We have some unique indexes, which I just learned can't be made to be unusable. It seems we will havee to drop & recreate them.

So once the indexes are dropped, how would you suggest we recreate them?

Tom Kyte
January 09, 2004 - 10:18 am UTC

you perhaps should consider using non-unique indexes

unique constraints and primary keys may both make use of non-unique indexes, no problems.


otherwise, you are "on your own" to recreate them using "create index"

Using non-unique index for PK

Arun Gupta, January 09, 2004 - 11:44 am UTC

Tom,
From a best practices standpoint, would you recommend using non-unique indexes to enforce PK constraint? I asked this question long time ago on Metalink and someone very emphatically replied that this should be avoided to minimize confusion.
Thanks


Tom Kyte
January 09, 2004 - 2:12 pm UTC

there cannot be any confusion.


you see -- a primary key constraint is a primary key constraint.

The existence (or lack thereof) of an index is "not even a teeny bit relevant".


The constraint is what is relevant.
An index is just a data structure.

Deferrable constraints (especially in a warehouse) are pretty nice, very flexible and they will generate non-unique indexes for primary keys (if an index does not already exist)

A primary key constraint might not even create a new index -- it can use any existing index that has the primary key columns on the leading edge.



Pauline, January 09, 2004 - 11:57 am UTC

Tom,
Recently I find many links you gave from your answer don't provide exact pages from the link. For example, when I click
the link you provide for the answer of regarding the question 'Using of UNUSABLE indexes,

</code> http://download-west.oracle.com/docs/cd/B10501_01/server.920/a96540/statements_22a.htm#2182515

I get the page which is 

http://otn.oracle.com/documentation/index.html <code>

Is any tricky thing to get the link?

Thanks.


Tom Kyte
January 09, 2004 - 2:19 pm UTC

otn/technet moved all of the documents one day.

But basically -- the part number is in there "a96540"...

so,

</code> http://docs.oracle.com/docs/cd/B10501_01/server.920/a96540/toc.htm

get's us to the document now (see the part number near the end) and most times


http://docs.oracle.com/docs/cd/B10501_01/server.920/a96540/statements_22a.htm#2182515 <code>

gluing the trailing end on will work. but that is the corrected link.

A reader, January 09, 2004 - 12:10 pm UTC

Pauline,Tom had a note on his front page which said OTN has moved all the links and i right now i cannot do anything about that, didn't you read that.



Tom Kyte
January 09, 2004 - 2:19 pm UTC

(sorry - i took that off, it had been up for a long time already...)

A reader, January 09, 2004 - 12:21 pm UTC

A Reader,
Thanks very much for telling me about it. I didn't know/read it. Can I still see this front page now?

Thanks.

A reader, January 09, 2004 - 12:26 pm UTC

A Reader,
Thanks very much for telling me about it. I didn't know/read it. Can I still see this front page now?

Thanks.

A Reader, January 09, 2004 - 12:56 pm UTC

Tom,
Could you provide how to create unique constraints and primary keys and make them use of non-unique indexes?

When I add PK to the table, Oracle will automatically create
unique indexe for the PK. If I want to create a non-unique index for this PK, Oracle will say
ORA-01408: such column list already indexed

Also I could not drop that unique index unless I do drop
that PK constraint. Otherwise will get:

ORA-02429: cannot drop index used for enforcement of unique/primary key

Thanks.



Tom Kyte
January 09, 2004 - 2:22 pm UTC

create the constraint "deferrable" and it'll use non-unique indexes.


index the columns and THEN add the constraints and the constraint will "kidnap" the index (non-unique index)




Non-unique index

A reader, August 10, 2004 - 3:24 pm UTC

Just curious...how does Oracle enforce a PK constraint using a non-unique index? 

create table t (i int);
create index idx on t(i);
alter table t add primary key(i);

bgi> insert into t values (1);

1 row created.

SQL> /
insert into t values (1)
*
ERROR at line 1:
ORA-00001: unique constraint (SYS_C0076675) violated

How does Oracle know that 1 is already in there? By looking it up in the index, right? 

This sounds so trivial i.e. when there is at least 1 entry in the index for that data, throw a ORA-00001 to enforce the PK.

But wasnt it until very recently that Oracle seemed to <b>require</b> a unique index to enforce a PK constraint?

Thanks 

Tom Kyte
August 10, 2004 - 4:00 pm UTC

it just does, it just needs an index -- doesn't have to be unique.

it has been well over 7 years (writing this in august of 2004) that deferrable constraints, which need the non-unique index, have been a feature of the database.

How to?

A reader, August 10, 2004 - 3:29 pm UTC

"create the constraint "deferrable" and it'll use non-unique indexes. index the columns and THEN add the constraints and the constraint will "kidnap" the index (non-unique index)"

I have a table with a PK constraint which automatically created the UNIQUE index. How can I modify this to use a non-unique index?

Not sure I understand your suggestion above, how can I create the constraint deferrable, it is already created.

I have the following

SQL> create table t (i int primary key);

Table created.

SQL> select INDEX_NAME,TABLE_NAME, UNIQUENESS from user_indexes where table_name='T';

INDEX_NAME                     TABLE_NAME                     UNIQUENES
------------------------------ ------------------------------ ---------
SYS_C0076676                   T                              UNIQUE

Now, how can I modify the index to be non-unique and still keep the PK constraint?

Thanks

 

Tom Kyte
August 10, 2004 - 4:01 pm UTC

you have to drop and recreate it. (or disable it, create non-unique index, and re-enable it -- but the constraint won't be deferrable -- to make it deferreble mandates a drop/create)

Deferrable

A reader, August 10, 2004 - 4:15 pm UTC

SQL> create table t (i int primary key);

Table created.

SQL> set lines 200                     
SQL> select INDEX_NAME,TABLE_NAME, UNIQUENESS from user_indexes where table_name='T';

INDEX_NAME                     TABLE_NAME                     UNIQUENES
------------------------------ ------------------------------ ---------
SYS_C0076677                   T                              UNIQUE

SQL> alter table t disable primary key;

Table altered.

SQL> create index idx on t(i);

Index created.

SQL> alter table t enable primary key;

Table altered.

SQL> select INDEX_NAME,TABLE_NAME, UNIQUENESS from user_indexes where table_name='T';

INDEX_NAME                     TABLE_NAME                     UNIQUENES
------------------------------ ------------------------------ ---------
IDX                            T                              NONUNIQUE

SQL> insert into t values (1);

1 row created.

SQL> /
insert into t values (1)
*
ERROR at line 1:
ORA-00001: unique constraint (SYS_C0076677) violated

Ok this works fine, I didnt get your comment about deferrable? How does deferrable come into the picture here? The PK constraint doesnt <b>have</b> to be deferrable to use a non-unique index, does it?

Thanks 

Tom Kyte
August 10, 2004 - 4:26 pm UTC

your primary key contraint is not deferrable -- that is what I meant (actually, thats what i said?)


if you want just a non-unique index for *whatever* reason -- disable, create index, enable.

if you want a deferrable constraint -- drop, create.



Typo???

Logan Palanisamy, August 10, 2004 - 8:52 pm UTC

Tom,

I think you meant

"if you want just a NON-unique index for *whatever* reason -- disable, create index, enable."

instead of

"if you want just a unique index for *whatever* reason -- disable, create index, enable."





Tom Kyte
August 11, 2004 - 7:28 am UTC

yes, thanks, fixed.

Primary Key constraint and index

A reader, September 08, 2004 - 6:06 am UTC

Hi Tom,
I created a PK on a table with index created on specific tablespace (using clause:- alter table add constraint....primary key using index tablespace...). Before loading data warehouse data, I disable primary key. After the load is finished, I enabled PK. When I enabled PK, it was trying to create index in default tablespace of the user. Is it possible that while enabling it should go into the tablespace where it was created initially?
Thanks & Regards

Tom Kyte
September 08, 2004 - 10:04 am UTC

ops$tkyte@ORA9IR2> create table t ( x int, y int );
 
Table created.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> alter table t add constraint t_pk primary key(x)
  2  using index tablespace tools;
 
Table altered.
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> select segment_name, tablespace_name from user_segments;
 
SEGMENT_NAME                   TABLESPACE_NAME
------------------------------ ------------------------------
T                              USERS
T_PK                           TOOLS
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> alter table t disable constraint t_pk;
 
Table altered.
 
ops$tkyte@ORA9IR2> alter table t enable constraint t_pk;
 
Table altered.
 
ops$tkyte@ORA9IR2> select segment_name, tablespace_name from user_segments;
 
SEGMENT_NAME                   TABLESPACE_NAME
------------------------------ ------------------------------
T                              USERS
T_PK                           USERS
 
ops$tkyte@ORA9IR2>
ops$tkyte@ORA9IR2> alter table t disable constraint t_pk;
 
Table altered.
 
ops$tkyte@ORA9IR2> alter table t enable constraint t_pk<b> using index tablespace tools;</b>
 
Table altered.
 
ops$tkyte@ORA9IR2> select segment_name, tablespace_name from user_segments;
 
SEGMENT_NAME                   TABLESPACE_NAME
------------------------------ ------------------------------
T                              USERS
T_PK                           TOOLS
 

Tablespace name

A reader, September 08, 2004 - 4:54 pm UTC

Hi Tom,
Thanks a lot for this. So, I have to specify the tablespace name again. Actually, this all code is in database procedure, so I thought there could be some way in database to handle this????
Regards

Tom Kyte
September 08, 2004 - 7:15 pm UTC

query it out in the beginning.

there are tricks you could play with deferrable constraints, non-unique indexes to enforce uniqueness, skipping unusable indexes, and the like but i think the easiest thing is "query it out at the begining and remember it"


Thanks a lot!

A reader, September 09, 2004 - 4:37 pm UTC

Hi Tom,
I got your point.
Regards

Split partition

Yogesh, February 04, 2005 - 11:58 am UTC

Oracle v8.0.4

I used following command for spliting existing partition

ALTER TABLE EIBTC1.EMP_LIST SPLIT PARTITION p1_02 AT ( TO_DATE(' 2002-12-31 23:59:59', 'SYYYY-MM-DD HH24:MI:SS') )
INTO ( PARTITION p1_02 TABLESPACE users , PARTITION p1_03 TABLESPACE users ) paralle( degree 8) , After using this command my PK index is unusable. I want to avaoid that.

Actually I want to split a table (size 12G + index 10 G) partition size 5G & indexes of same size. Permitted downtime, not more than 3 hours. I think this operation will take more time. So looking out for some options.




Tom Kyte
February 04, 2005 - 12:16 pm UTC

time really for you to upgrade to this century -- everything you seem to want to do is available, only not in super old software.....


sorry, index maintainence didn't exist way back then.


(but if you cannot do that in 3 hours -- with just 12g of table data, you need new hardware too, that is a smsll amount of data there)

UNUSABLE Indexes on MV's

Jim J., February 04, 2005 - 1:35 pm UTC

I have a related question regarding unusable indexes:

I've built some bitmap indexes on a materialized view which is completely refreshed on a regular basis. Before refreshing the MV, I mark the indexes as unusable. The refresh ignores this information and rebuild's the indexes anyway. According to the Data Warehousing Guide, refreshing a materialized view will all of it's indexes. But it also states that you can mark indexes as unuable prior to a refresh. 

Example (version 9.2.0.1.0):

SQL> create materialized view test_mv
  2  build deferred
  3  using no index
  4  refresh force on demand
  5  as select * from emp;

Materialized view created.

SQL> create bitmap index test_mv_bx on test_mv(job)
  2  nologging nocompress;

Index created.

SQL> alter index test_mv_bx unusable;

Index altered.

SQL> select status from user_indexes where index_name='TEST_MV_BX';

STATUS
--------
UNUSABLE

SQL> alter session set skip_unusable_indexes=true;

Session altered.

SQL> exec dbms_mview.refresh('test_mv','c')

PL/SQL procedure successfully completed.

SQL> select status from user_indexes where index_name='TEST_MV_BX';

STATUS
--------
VALID

The index is rebuilt during the refresh, even though it is UNUSABLE.
Is this expected behavior? Is there any way to supress rebuilding the indexes until after the refresh? While this example does not show it (due to the small amount of data), rebuilding the bitmap index during the refresh creates a much larger index than if it is rebuilt after the refresh is complete. It also causes the refresh to take a longer amount of time.

I realize that one option is to drop the indexes before the refresh and then recreate them, but I would prefer not having to do this (keeping the index definitions in the data dictionary and simply rebuilding those that are unusable seems much more elegant).

Thank you in advance for your input. 

Tom Kyte
February 04, 2005 - 2:19 pm UTC

well, a single table full refresh issues "truncate", which makes all of the indexes "usable" and then does an "insert /*+ APPEND */" which will build the index nicely at the end.

so, it is probably OK

if you want, you would create a snapshot refresh group (add a snapshot on dual for example). then you would

a) delete
b) insert

you might find that slower over all however.

split partition

Yogesh, February 05, 2005 - 10:57 am UTC

12 G is not a big volume. Agreed.

But in this case 3 operations are involved

1. Partition split
2. Rebuilding all indexes
3. Analyzed table partitons and indexes

I guess 3 hours is bit less. My guess could be wrong as well ;-)

From which version onward we can avoid this unusable problem?

Tom Kyte
February 05, 2005 - 11:02 am UTC

well, it is not that is would "take less time" either - it is that the indexes can be maintained during the split (useful for a data warehouse)

You would have to still "maintain" the indexes -- which truth be told probably takes longer than a rebuild.


but even so, a split of 12gig (nologging), rebuild the indexes (parallel, nologging), analyze estimate, 3 hours should be ok.


when you do this on your test system, how fast can you make it go?


split partition

Yogesh, February 07, 2005 - 7:07 am UTC

My test and production hardware is different. Test system is a dual CPU machine and prod is 8 CPU. They don't have same RAM either, so it'll be like comparing "apple Vs orange" in your terms ;)

Tom Kyte
February 07, 2005 - 8:43 am UTC

you expect this to be rather disk intensive, it would be worth your time to practice this in test and you would get a feeling for what you can expect.

A reader, May 24, 2005 - 2:10 pm UTC


skip_unusable_indexes

A reader, March 18, 2006 - 8:29 am UTC

In 9i Release 2 
when I do
SQL> 
SQL> 
SQL> show parameter skip_unusable_indexes ;
SQL> alter session set skip_unusable_indexes=true;

Session altered.

Why does show parameter dont work? it shows nothing in this case.

How can we see the current value of session only parameters 

Tom Kyte
March 18, 2006 - 4:38 pm UTC

because show parameter queries v$parameter, which shows SYSTEM parameters.

skip_unusable_indexes is not something you can set in the init.ora for example.

.

A reader, March 19, 2006 - 11:35 am UTC

But there must be some way by which I can
see the current setting of my session only paramters.

Tom Kyte
March 19, 2006 - 2:15 pm UTC

not necessarily.

session only parameters

A reader, March 22, 2006 - 3:20 am UTC

Ok, I contacted metalink support on this and here
is a copy/paste from metalink.

+ There is no view to check the settings of session only parameters.
+ This specific parameter - SKIP_UNUSABLE_INDEXES, which in earlier releases was a session parameter,is now an initialization para
meter in 10g with a default value of TRUE. So one can see its current value in
a session using show parameter in 10g.
+ This same parameter cannot viewed by show parameter in 9i as this was a session only paramter in prior to 10g releases