Oracle主鍵約束、唯一鍵約束、唯一索引的區別(轉)

langgufu314發表於2012-12-11

一般,我們看到術語“索引”和“鍵”交換使用,但實際上這兩個是不同的。索引是儲存在資料庫中的一個物理結構,鍵純粹是一個邏輯概念。鍵代表建立來實施業務規則的完整性約束。索引和鍵的混淆通常是由於資料庫使用索引來實施完整性約束。

 

接下來我們看看資料庫中的主鍵約束、唯一鍵約束和唯一索引的區別。

SQL> select * from v$version;

 

BANNER

--------------------------------------------------------------------------------

Oracle Database 11g Enterprise Edition Release 11.2.0.1.0 - Production

PL/SQL Release 11.2.0.1.0 - Production

CORE 11.2.0.1.0 Production

TNS for Linux: Version 11.2.0.1.0 - Production

NLSRTL Version 11.2.0.1.0 - Production

 

SQL> create table test (

2 id int,

3 name varchar2(20),

4 constraint pk_test primary key(id))

5 tablespace users;

 

Table created.

 

SQL> select constraint_name, constraint_type from user_constraints;

 

CONSTRAINT_NAME C

------------------------------ -

PK_TEST P

 

test表中,我們指定了ID列作為主鍵,Oracle資料庫會自動建立一個同名的唯一索引:

SQL> select index_name, index_type, uniqueness, tablespace_name

2 from user_indexes

3 where table_owner='SCOTT'

4 and table_name = 'TEST';

 

INDEX_NAME INDEX_TYPE UNIQUENES TABLESPACE_NAME

-------------------- -------------------- --------- ------------------------------

PK_TEST NORMAL UNIQUE USERS

 

此時,如果我們再試圖在ID列上建立一個唯一索引,Oracle會報錯,因為該列上已經存在一個唯一索引:

SQL> create unique index idx_test_uk on test(id);

create unique index idx_test_uk on test(id)

*

ERROR at line 1:

ORA-01408: such column list already indexed

即使建立非唯一索引也不行:

SQL> create index idx_test_id on test(id);

create index idx_test_id on test(id)

*

ERROR at line 1:

ORA-01408: such column list already indexed

 

那麼唯一鍵約束的情況是怎樣的呢?

SQL> drop table test purge;

 

Table dropped.

 

SQL> create table test(

2 id int,

3 name varchar2(20),

4 constraint uk_test unique(id));

 

Table created.

 

SQL> select constraint_name, constraint_type from user_constraints;

 

CONSTRAINT_NAME C

------------------------------ -

UK_TEST U

 

檢視此時的索引情況:

SQL> select index_name, index_type, uniqueness, tablespace_name

2 from user_indexes

3 where table_owner='SCOTT'

4 and table_name = 'TEST';

 

INDEX_NAME INDEX_TYPE UNIQUENES TABLESPACE_NAME

-------------------- -------------------- --------- ------------------------------

UK_TEST NORMAL UNIQUE USERS

Oracle同樣自動建立了一個同名的唯一索引,而且也不允許再在此列上建立唯一索引或非唯一索引。

 

我們知道,主鍵約束要求列值非空(NOT NULL),那麼唯一鍵約束是否也要求非空呢?

SQL> insert into test values(1, 'Sally');

 

1 row created.

 

SQL> insert into test values(null, 'Tony');

 

1 row created.

 

SQL> insert into test values(null, 'Jack');

 

1 row created.

 

SQL> select * from test;

 

ID NAME

---------- --------------------

1 Sally

Tony

Jack

從實驗結果來看,唯一鍵約束並沒有非空要求。

 

接下來我們看看唯一索引對列值的非空要求有什麼不同。

SQL> drop table test purge;

 

Table dropped.

 

SQL> create table test(

2 id int,

3 name varchar2(20));

 

Table created.

 

SQL> create unique index idx_test_id on test (id);

 

Index created.

 

SQL> insert into test values(1, 'Sally');

 

1 row created.

 

SQL> insert into test values(null, 'Tony');

 

1 row created.

 

SQL> insert into test values(null, 'Jack');

 

1 row created.

 

SQL> select * from test;

 

ID NAME

---------- --------------------

1 Sally

Tony

Jack

通過實驗,我們看出唯一索引與唯一鍵約束一樣對列值非空不做要求。

 

如果我們讓主鍵約束或者唯一鍵約束失效,Oracle自動建立的唯一索引是否會受到影響?

SQL> drop table test purge;

 

Table dropped.

 

SQL> create table test(

2 id int,

3 name varchar2(20),

4 constraint uk_test unique(id));

 

Table created.

 

SQL> select index_name, index_type, uniqueness from user_indexes;

 

INDEX_NAME INDEX_TYPE UNIQUENES

------------------------------ --------------------------- ---------

UK_TEST NORMAL UNIQUE

 

SQL> alter table test disable constraint uk_test;

 

Table altered.

 

SQL> select index_name, index_type, uniqueness from user_indexes;

 

no rows selected

當主鍵約束或者唯一鍵約束失效時,Oracle會刪除隱式建立的唯一索引。

 

如果我們先建立唯一索引,再建立主鍵或者唯一鍵約束,情況又會怎樣呢?

SQL> drop table test purge;

 

Table dropped.

 

SQL> create table test(

2 id int,

3 name varchar2(20));

 

Table created.

 

SQL> create unique index idx_test_id on test (id);

 

Index created.

 

SQL> select index_name, index_type, uniqueness

2 from user_indexes

3 where table_owner = 'SCOTT'

4 and table_name = 'TEST';

 

INDEX_NAME INDEX_TYPE UNIQUENES

------------------------------ --------------------------- ---------

IDX_TEST_ID NORMAL UNIQUE

 

SQL> alter table test add constraint uk_test unique (id);

 

Table altered.

 

SQL> select index_name, index_type, uniqueness

2 from user_indexes

3 where table_owner = 'SCOTT'

4 and table_name = 'TEST';

 

INDEX_NAME INDEX_TYPE UNIQUENES

------------------------------ --------------------------- ---------

IDX_TEST_ID NORMAL UNIQUE

 

SQL> select constraint_name, constraint_type

2 from user_constraints

3 where table_name = 'TEST';

 

CONSTRAINT_NAME C

------------------------------ -

UK_TEST U

 

SQL> alter table test disable constraint uk_test;

 

Table altered.

 

SQL> select constraint_name, constraint_type, status

2 from user_constraints

3 where table_name = 'TEST';

 

CONSTRAINT_NAME C STATUS

------------------------------ - --------

UK_TEST U DISABLED

 

SQL> select index_name, index_type, uniqueness, status

2 from user_indexes

3 where table_owner = 'SCOTT'

4 and table_name = 'TEST';

 

INDEX_NAME INDEX_TYPE UNIQUENES STATUS

------------------------------ --------------------------- --------- --------

IDX_TEST_ID NORMAL UNIQUE VALID

 

實驗結果表明,先建立的唯一索引不受約束失效的影響。

 

總結如下:

1)主鍵約束和唯一鍵約束均會隱式建立同名的唯一索引,當主鍵約束或者唯一鍵約束失效時,隱式建立的唯一索引會被刪除;

2)主鍵約束要求列值非空,而唯一鍵約束和唯一索引不要求列值非空;

3)相同欄位序列不允許重複建立索引;

相關文章