2011-09-22 247 views
34

有人可以澄清沒有唯一約束(Oracle)的情況下擁有唯一索引的目的是什麼? 例如,Oracle唯一約束和唯一索引

create table test22(id int, id1 int, tmp varchar(20)); 
create unique index idx_test22 on test22(id); 
insert into test22(id, id1, tmp) values (1, 2, 'aaa'); // ok 
insert into test22(id, id1, tmp) values (1, 2, 'aaa'); // fails, ORA-00001: unique 
    // constraint (TEST.IDX_TEST22) violated 

到目前爲止,它看起來像有一個約束。但是

create table test33(id int not null primary key, 
test22_id int not null, 
foreign key(test22_id) references test22(id)); 

也因爲"ORA-02270: no matching unique or primary key for this column-list"而失敗。 我完全被這種行爲所困惑。有沒有約束?

有許多文章解釋了爲什麼可能有唯一的約束沒有唯一的索引;這是清楚的,非常有意義。但是,我不明白沒有約束的唯一索引的原因。

回答

39

約束和索引是分離的邏輯實體。例如,唯一約束在USER_CONSTRAINTS(或ALL_CONSTRAINTSDBA_CONSTRAINTS)中可見。索引在USER_INDEXES(或ALL_INDEXESDBA_INDEXES)中可見。

一個唯一的約束是由一個索引強制執行的,雖然有可能(有時需要)使用非唯一索引強制執行一個唯一約束。例如,可延遲的唯一約束是使用非唯一索引實施的。如果您在列上創建非唯一索引並隨後創建唯一約束,則還可以使用該非唯一索引來強制執行唯一約束。

實際上,唯一索引非常像一個獨特的不可延遲約束,因爲唯一約束的實現使用該索引,所以它引發了唯一約束引發的相同錯誤。但這並不完全相同,因爲沒有限制。所以,正如你所看到的,沒有唯一的約束,所以你不能創建引用列的外鍵約束。

有些情況下,您可以創建一個唯一的索引,但不能創建唯一的約束。例如,基於函數的索引強制條件唯一性。如果我想創建一個支持邏輯刪除表,但確保COL1是所有非刪除的行唯一

SQL> ed 
Wrote file afiedt.buf 

    1 CREATE TABLE t (
    2 col1 number, 
    3 deleted_flag varchar2(1) check(deleted_flag in ('Y','N')) 
    4*) 
SQL>/

Table created. 

SQL> create unique index idx_non_deleted 
    2  on t(case when deleted_flag = 'N' then col1 else null end); 

Index created. 

SQL> insert into t values(1, 'N'); 

1 row created. 

SQL> insert into t values(1, 'N'); 
insert into t values(1, 'N') 
* 
ERROR at line 1: 
ORA-00001: unique constraint (SCOTT.IDX_NON_DELETED) violated 


SQL> insert into t values(1, 'Y'); 

1 row created. 

SQL> insert into t values(1, 'Y'); 

1 row created. 

但是,如果我們談論的是一個直獨特的非功能基指數,有可能是相對少數情況下,創建索引而不是創建約束確實更有意義。另一方面,在實踐中差異很大的情況相對較少。你幾乎從不想聲明引用唯一約束而不是主鍵約束的外鍵約束,所以你很少會失去一些東西,只創建索引而不創建約束。

+0

感謝您的回答,現在已經越來越清晰了。我真正不喜歡的是兩種情況下的相同錯誤代碼('ORA-00001'),約束和唯一索引。 – a1ex07

+0

非常好,感謝您的「最終決定權」,感謝您是否可以在獨特的FBI上創建獨特的約束。 – orbfish

+0

謝謝 - 這是我找到的兩個差異的唯一明確解釋。 我見過一些提到,聲明一個唯一的約束爲優化器提供了比唯一索引更多的信息.​​..這是否是真的,這是否意味着一個獨特的約束可以在沒有約束的情況下爲獨特的索引提供一些性能優勢? – Mike

1

在這種情況下可能有用的另一點是: 禁用/刪除現有唯一約束不會刪除基礎唯一索引。你必須明確地刪除唯一索引。

+2

這是不正確的(至少10g)。事實上,你必須指定'KEEP INDEX',同時刪除唯一約束來保持索引。另外,索引不一定是唯一的。 – a1ex07

+0

有趣。但是,它不是11g。 – Syamjith