Unusable unique constraint

Another annoying thing about unusable indexes

I’m surprised that I can’t remember coming across this before before.

I want to archive some data from a bunch of partitions.

Unfortunately, I can’t follow the virtuous circle of data lifecycling and partition the table in such a way that I can archive all the data from a particular partition (or subpartition) via exchange partition.

Without going into too much detail and skipping a bunch of other steps, roughly what I wanted to do was:
1. Mark indexes as unusable (ignore whether they’re global/local, it doesn’t matter).
2. Delete from existing partition
3. Rebuild indexes.

But if you mark a unique index as unusable, you can’t then do DML on the table.

It is expected behaviour.
Doesn’t matter what the setting of skip_unusable_indexes is.

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.

Well that seems to compromise one of the main benefits of marking a unique index as unusable.

SQL> get tmp
  1  drop table t1;
  2  create table t1
  3  (pt    varchar2(24)
  4  ,col1  number)
  5  PARTITION BY LIST (pt)
  6  (PARTITION PX VALUES('X')
  7  ,PARTITION PY VALUES('Y'));
  8  create unique index i1 on t1 (col1) global;
  9  insert into t1 values ('X',1);
 10  alter index i1 unusable;
 11* delete from t1 partition (px) where col1 = 1;
 12  .
SQL> @tmp

Table dropped.

Table created.

Index created.

1 row created.

Index altered.

delete from t1 partition (px) where col1 = 1
*
ERROR at line 1:
ORA-01502: index 'E668983_DBA.I1' or partition of such index is in unusable state

To get around this, I can use a unique constraint backed by a non-unique index but that can come with some extra baggage.

SQL> get tmp
  1  drop table t1;
  2  create table t1
  3  (pt    varchar2(24)
  4  ,col1  number)
  5  PARTITION BY LIST (pt)
  6  (PARTITION PX VALUES('X')
  7  ,PARTITION PY VALUES('Y'));
  8  create  index i1 on t1 (col1) global;
  9  alter table t1 add constraint uk_t1 unique (col1) using index i1;
 10  insert into t1 values ('X',1);
 11  alter table t1 disable constraint uk_t1;
 12  alter index i1 unusable;
 13* delete from t1 partition (px) where col1 = 1;
 14  .
SQL> @tmp

Table dropped.

Table created.

Index created.

Table altered.

1 row created.

Table altered.

Index altered.

1 row deleted.

3 Responses to Unusable unique constraint

  1. hourim says:

    Hi Dominic,

    There is for sure a way to do DML on table having unique unusable index. At least this is what Oracle is doing internally when direct pathing via SQL Loader or when refreshing materialized view with the atomic refresh parameter set to FALSE (truncate + insert append). I have blogged about that here

    CBO and unusable unique index

    I have tried to do it myself using the hint insert /*+ skip_unq_unusable_idx */ but I have been unsuccessful. There is a supplementary flag or something else set by Oracle internally in addition to the use of the skip_unq_unusable_idx

    The workaround you are using (policing the unique constraint with a non-unique index) is the right one I believe. When re-enabling the unique constraint again you can use the exception table if you want

    On constraint validation : use of Exception table

    Best regards
    Mohamed Houri
    http://www.hourim.wordpress.com

  2. Dominic,

    Regarding the option to use a non-unique index to support a unique constraint Randolf Geist recently mentioned on OTN that this strategy could even result in a situation where the enabled and validated constraint is violated without any error message – https://community.oracle.com/message/12301790#12301790 – when the insert is done via direct path. This seems to be fixed in 11.2.0.4.

    Regards

    Martin

  3. Pingback: Reluctant Local Index | OraStory

Leave a comment