Does columns order in multiple columns unique constraint make any difference? Is it justifiable to have duplicate indexes?

StackOverflow https://stackoverflow.com/questions/17614025

Question

In "SQL Certified Expert Exam Guide" by Steve O'Hearn I've found this paragraph:

In the rare instance when you create a composite index along with multiple constraints that call on the same index, a special syntax is required. For example, if we decide to create a composite index on both of our columns in the INVOICES table, we can use this syntax:

CREATE TABLE invoices
(
    invoice_id    NUMBER(11),
    invoice_date  DATE,
    CONSTRAINT    un_invoices_invoice_id UNIQUE (invoice_id, invoice_date)
                  USING INDEX (CREATE INDEX ix_invoices
                                      ON invoices(invoice_id, invoice_date)),
    CONSTRAINT    un_invoices_invoice_date UNIQUE (invoice_date, invoice_id)
                  USING INDEX ix_invoices
);

And here're my questions:

  1. What's the point in creating two unique constraints changing only columns order in declaration?

  2. We've create one multiple-column index: "invoice_id" as first column and "invoice_date" as second column. But let's assume that we really often run queries that relate to "invoice_date" itself, without "invoice_id" participation. Would it be a good idea to create second, single column index on "invoice_date"? I know that:

Because Oracle supports multi-column indexes, it’s easy to accidently create “duplicate” indexes, indexes that add overhead to DML and do not aid in speeding-up SQL execution. [Source]

and I also know that:

Thanks to skip scanning a WHERE clause that references any columns within a composite index may invoke the index in its processing. [Steve O'Hearn]

but also I know that:

This isn't quite as beneficial as a simple one-column index, and its benefit varies, depending on the uniqueness of values in the first column. [Steve O'Hearn]

So let's assume that we rarely use DML commands on this table and let's assume that we relate to both columns in SELECT's WHERE clause as often as to "index_date" or "index_id" separately. Would it be justified, in certain situations, to create two indexes? One, multiple column index, on (index_id, index_date) and second, single column index, on (index_date)?

Was it helpful?

Solution 2

Your question is:

Would it be justified, in certain situations, to create two indexes? One, multiple column index, on (index_id, index_date) and second, single column index, on (index_date)?

The answer is "yes". The first index will be used to satisfy queries with conditions like:

  • filtering on index_id in the where clause
  • filtering on index_id and index_date in the where clause
  • filtering on index_id in the where clause and the ordering by index_date

The second index would not be used in these circumstance. It would be used for:

  • filtering on index_date in the where clause

And the first index would not be used in this case.

The ordering of columns in indexes is important. They are used from the left to the right. So, these two indexes are useful. However, a third index on index_id alone would not be useful, because the first index already takes care of the same situations where that index would be used.

OTHER TIPS

You asked

"What's the point in creating two unique constraints changing only columns order in declaration?"

There isn't any point. The order of columns in a composite constraint doesn't make any difference:

SQL> select * from t23
  2  /

      COL1 COL
---------- ---
         1 WTF

SQL> create index t23_i on t23(col1, col2);

Index created.

SQL> alter table t23 add constraint t23_uk unique (col1 , col2) using index t23_i
  2  /

Table altered.

SQL> insert into t23 values (1, 'WTF')
  2  /
insert into t23 values (1, 'WTF')
*
ERROR at line 1:
ORA-00001: unique constraint (APC.T23_UK) violated


SQL> alter table t23 drop  constraint t23_uk
  2  /

Table altered.

SQL> alter table t23 add constraint t23_uk unique (col2, col1) using index t23_i
  2  /

Table altered.

SQL> insert into t23 values (1, 'WTF')
  2  /
insert into t23 values (1, 'WTF')
*
ERROR at line 1:
ORA-00001: unique constraint (APC.T23_UK) violated


SQL> 

That's the problem with exam-crammers: they often just say stuff, without providing explanation or context.

You also asked:

" Would it be a good idea to create second, single column index on invoice_date?"

Without knowing the data it's hard to tell, but I would expect a date column to be less selective than an ID column (especially if the time element is truncated), so generally I would expect an index to built as (invoice_date, invoice_id) anyway. That might allows us to use index compression.

Skip-scanning doesn't quite work as Steve states: it starts by probing the leading edge of the index, but only if the second column in the composite index is referenced in the WHERE clause. The optimizer might choose a Full Fast Index Scan for searching on third columns or lower. Also it won't choose a Skip Scan path if the leading edge has too many distinct values: another good reason for leading with columns of low selectively.

So, this doesn't exactly answer your question, but I think it does convey an important point: there are no universal rules governing creating indexes for performance. We need to understand the profile of the data - its values distribution and volumes - and also the most important queries which will use the table.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top