jump to navigation

Primary Keys and Non-Unique Indexes (What’s Really Happening ?) June 4, 2008

Posted by Richard Foote in Constraints, Oracle General, Oracle Indexes, Oracle Myths, Primary Key.
trackback

Based on this OTN thread, it appears there may still be folk out there that think Oracle uses Unique Indexes to police a Primary Key (or Unique Key) constraint. This is of course not necessarily true as since 8.0 and the introduction of Deferrable Constraints, Oracle can just as easily police a PK (or UK) constraint with a Non-Unique Index.

To determine whether a new PK value currently exists or not, Oracle can almost (although not quite) just as easily perform an index look-up using a Non-Unique Index as it can with a Unique Index. Simple index look-up, is the value there, yes or no, proceed as appropriate.

Indeed, I’ve already discussed on these here pages various differences between using a Unique and a Non-Unique Index:

http://richardfoote.wordpress.com/2007/12/18/differences-between-unique-and-non-unique-indexes-part-i/

http://richardfoote.wordpress.com/2007/12/21/differences-between-unique-and-non-unique-indexes-part-ii/

http://richardfoote.wordpress.com/2007/12/30/differences-between-unique-and-non-unique-indexes-part-iii/

However, for those that may never have seen a case where creating a PK constraint has not created a Unique index, I thought it might be an idea to just go through a number of different scenarios when this is all quite possible.

The first example is when there’s already an existing non-unique index that Oracle can use. Oracle will not (and indeed can not) create a Unique Index where an identical Non-Unique index already exists.

SQL> create table bowie as select rownum id, ‘BOWIE’ text from dual connect by level <= 10000;

 

Table created.

 

SQL> create index bowie_i on bowie(id);

 

Index created.

 

SQL> alter table bowie add constraint bowie_pk primary key(id);

 

Table altered.

 

SQL> select ic.index_name, ic.column_name, i.uniqueness, c.constraint_name, c.constraint_type from user_ind_columns ic, user_indexes i, user_constraints c where ic.index_name = i.index_name and i.index_name = c.index_name and i.index_name =  ’BOWIE_I’;

 

INDEX_NAME COL_NAME UNIQUENES CON_NAME C
---------- -------- --------- -------- -
BOWIE_I    ID       NONUNIQUE BOWIE_PK P

A subtle difference to this scenario is where there’s an existing Non-Unique index but it only has the leading columns the same as the PK constraint to be. Again, even if there are additional columns within the index, the fact the leading columns match the PK constraint means Oracle can still use the index to police the constraint as the index must be in the same logical order of these leading columns.

For example:

SQL> alter table bowie drop primary key;

 

Table altered.

 

SQL> drop index bowie_i;

 

Index dropped.

 

SQL> create index bowie_i on bowie(id, text);

 

Index created.

 

SQL> alter table bowie add constraint bowie_pk primary key(id);

 

Table altered.

 

SQL> select ic.index_name, ic.column_name, i.uniqueness, c.constraint_name, c.constraint_type from user_ind_columns ic, user_indexes i, user_constraints c where ic.index_name = i.index_name and i.index_name = c.index_name and i.index_name = ’BOWIE_I’;

 

INDEX_NAME COL_NAME UNIQUENES CON_NAME C
---------- -------- --------- -------- -
BOWIE_I    TEXT     NONUNIQUE BOWIE_PK P
BOWIE_I    ID       NONUNIQUE BOWIE_PK P

Another example is when the PK constraint is created as being DEFERRABLE. This means the constraint could be used to defer the policing of the constraint until the time of the COMMIT, rather than at the time of the DML statement. As such, for a period of time during a transaction, there could actually be duplicate values for the PK. Not only will Oracle create a Non-Unique index for such a Deferrable constraint, indeed Oracle MUST create a non-unique index. The existance of a previously created Unique Index will actually prevent Oracle from creating PK constraint as deferrable.

SQL> alter table bowie drop primary key;

 

Table altered.

 

SQL> drop index bowie_i;

 

Index dropped.

 

SQL> alter table bowie add constraint bowie_pk primary key(id) deferrable;

 

Table altered.

 

SQL> select ic.index_name, ic.column_name, i.uniqueness, c.constraint_name, c.constraint_type from user_ind_columns ic, user_indexes i, user_constraints c where ic.index_name = i.index_name and i.index_name = c.index_name and i.table_name = ’BOWIE’;

 

INDEX_NAME COL_NAME UNIQUENES CON_NAME C
---------- -------- --------- -------- -
BOWIE_PK   ID       NONUNIQUE BOWIE_PK P

Of course, another way to create a Non-Unique Index when defining a PK constraint is to simply create the specific index at the same time as the PK constraint. You can get pretty tricky with the create table syntax these days.

For example:

SQL> alter table bowie drop primary key;

 

Table altered.

 

SQL> drop index bowie_pk;

 

Index dropped.

 

SQL> alter table bowie add constraint bowie_pk primary key(id) using index (create index bowie_i on bowie(id));

 

Table altered.

 

SQL> select ic.index_name, ic.column_name, i.uniqueness, c.constraint_name, c.constraint_type from user_ind_columns ic, user_indexes i, user_constraints c where ic.index_name = i.index_name and i.index_name = c.index_name and i.table_name = ’BOWIE’;

 

INDEX_NAME COL_NAME UNIQUENES CON_NAME C
---------- -------- --------- -------- -
BOWIE_I    ID       NONUNIQUE BOWIE_PK P

The next time you read or hear mentioned Oracle uses a Unique Index to police a PK (or UK) constraint, you now know it might not necessarily be the case.

Comments»

1. Tony - June 4, 2008

Awesome as usual. For me, this is one of the best blogs on the interweb …the content just can’t be beat.

2. Amit - June 4, 2008

Excellent Post !! New learning :)

3. Brian Tkatch - June 5, 2008

Thanx Richard, good stuff.

4. Polarski Bernard - June 6, 2008

great reading

5. Richard Foote - June 6, 2008

Hi Folks

Thanks for the nice comments, much appreciated :)

6. Asif Momen - June 6, 2008

Superb !!!

7. SeánMacGC - June 6, 2008

All good Richard, many thanks.

8. lscheng - July 29, 2008

Hi

This sort of indexing techniques is mostly used in Data Warehouse environments

9. Vladimir - August 22, 2008

Hi Richard,

Ok, you showed that Oracle can create the primary key based on non-unique index. But I don’t understand how Oracle uses it if such constraint is needed unique values, but the non-unique index admits non-unique values.

Is it mean that Oracle will prohibit inserting of repeated values in corresponding column after creating ptimary key?
Or Oracle will permit inserting of repeated values, but must do overheads to support uniqueness of the primary key?

Thanks.

10. Brian Tkatch - August 22, 2008

Vladimir. How does a PK work anyway with a UNIQUE INDEX? Basically, when the system looks to put a new values it first checks if it already exists in the INDEX. If it does not yet exist, the new entry is allowed. This policing is done by the INDEX, so the PK itself does not need to do anything.

If the PK is using a non-UNIQUE INDEX, the process is exactly the same–it still checks if the value exists–, the only difference is, the PK “itself” does the checking.

As such, the difference would seem to be not what is done, but who does it.

11. Vladimir - August 22, 2008

Brian Tkatch.

That is, PK as a “structure-object-program” works differently against type of the based index.

Well, it looks like true.. One question only – is it your personal guess or it is a accessible knowledge (where can I read about it)? :)

Thanks.

12. Richard Foote - August 25, 2008

Hi Vladimir

Brian has explained things nicely.

The non-unique index can not admit non-unique values because the unique contraint won’t allow it (unless the constraint is deferrable or novalidated).

Therefore the non-unique index is quite as capable of determining whether a new index entry currently exists or it doesn’t as a unique index when policing the constraint.

13. Vladimir - August 25, 2008

Thanks Richard!

14. Vladimir - August 26, 2008

Hi Richard,

One notice only.

That is, in lighting of all above we can assert that Oracle have two types of PK. On creating PK Oracle detects the type of the index which will work in pair with PK. And then Oracle pick out corresponding type of PK..

Does it look like true?

15. Richard Foote - August 26, 2008

Hi Vladimir

No, that’s not quite correct.

A PK is a PK and without the fancy options, works the same regardless of it being policed by a Unique or Non-Unique Index.

However, a PK can be deferrable, which means the policing of the constraint is deferred until the time of the commit. In which case, it must be policed by a non-unique index.

A PK can also be created as novalidate. Which means the existing data is not checked for correctness when the constraint is created and so existing data can potentially violate the PK constraint.

These options are determined when the constraint is created and so an appropriate index (eg. non-unique index for a deferrable constraint) must be used/created at the time the constraint is established.

16. Vladimir - August 26, 2008

Hi Richard

Thanks for clarification. (One more step to understanding for me..) Yes, I already know about it (thanks to your posts).

But I can’t understand, why PK always use the index in it’s working. My suggestion is because of using of existing structure in the system (it is unnecessary to create extra policying structure) despite of all the index problems.

Is it correct now?