oracle 主键约束重名,主键及主键索引的关系及相互影响
主鍵的定義:列或多列的集合,用于唯一的標識表中的一行。一個表上只允許有一個主鍵。
我們在數據庫中指定主鍵時,是通過主鍵約束來定義的。而創建主鍵約束時,又是需要有相應的索引來配合實現的。所以,本文的目的是總結創建主鍵約束時,采用不同的方法創建索引后,主鍵與該索引之間的關系及相互影響。
為配合本文的描述和測試,首先創建如下測試表:
create table test (id number,c1 varchar2(8));
一、 首先,我們來看最常用的創建主鍵約束及索引的方法:
alter table t1 add constraint pk_test_id primary key (id);
創建完成后,檢查相應約束和索引視圖中的內容:
SQL> select constraint_name,constraint_type,table_name,status from user_constraints where table_name='TEST';
CONSTRAINT_NAME CO TABLE_NAME ? ?STATUS
--------------- -- --------------- ----------------
PK_TEST_ID ?P ?TEST ? ? ENABLED
從上可見,我們已經創建了一個名為“PK_TEST_ID”的主鍵約束,其當前狀態為有效狀態。
SQL> select index_name,uniqueness,table_name,status from user_indexes where table_name='TEST';
INDEX_NAME ?UNIQUENESS ? ? TABLE_NAME ? ? ? STATUS
--------------- ------------------ --------------- ----------------
PK_TEST_ID ?UNIQUE ? ? ? ? TEST ? ? ? ?VALID
從上可見,數據庫同時自動為該主鍵約束創建了一個同名的唯一索引。
如果這時,我們將主鍵約束關閉或者刪除,又會是什么情況呢?
SQL> alter table test disable constraint pk_test_id;
Table altered.
SQL> select constraint_name,constraint_type,table_name,status from user_constraints where table_name='TEST';
CONSTRAINT_NAME CO TABLE_NAME ? ?STATUS
--------------- -- --------------- ----------------
PK_TEST_ID ?P ?TEST ? ? DISABLED
SQL> select index_name,uniqueness,table_name,status from user_indexes where table_name='TEST';
no rows selected
可見,當我們把主鍵約束關閉后,其同名的索引被自動刪除了。
那如果我們不將主鍵約束關閉或者刪除,而是將自動創建的同名索引關閉或刪除,又會是什么情況呢?
SQL> alter table test enable constraint pk_test_id;
Table altered.
SQL> select constraint_name,constraint_type,table_name,status from user_constraints where table_name='TEST';
CONSTRAINT_NAME CO TABLE_NAME ? ?STATUS
--------------- -- --------------- ----------------
PK_TEST_ID ?P ?TEST ? ? ENABLED
SQL> select index_name,uniqueness,table_name,status from user_indexes where table_name='TEST';
INDEX_NAME ?UNIQUENESS ? ? TABLE_NAME ? ? ? STATUS
--------------- ------------------ --------------- ----------------
PK_TEST_ID ?UNIQUE ? ? ? ? TEST ? ? ? ?VALID
首先,我們先恢復被關閉的主鍵約束,發現約束的狀態已經恢復正常,而且同名的索引也被重建恢復了。現在我們將同名的索引關閉或刪除。
SQL> alter index pk_test_id unusable;
Index altered.
SQL> ?select constraint_name,constraint_type,table_name,status from user_constraints where table_name='TEST';
CONSTRAINT_NAME CO TABLE_NAME ? ?STATUS
--------------- -- --------------- ----------------
PK_TEST_ID ?P ?TEST ? ? ENABLED
SQL> ?select index_name,uniqueness,table_name,status from user_indexes where table_name='TEST';
INDEX_NAME ?UNIQUENESS ? ? TABLE_NAME ? ? ? STATUS
--------------- ------------------ --------------- ----------------
PK_TEST_ID ?UNIQUE ? ? ? ? TEST ? ? ? ?UNUSABLE
可見,當關閉索引后,除了索引的狀態變為UNUSABLE外,主鍵的狀態仍是正常狀態。但若此時向表中插入數據,則會報錯ORA-01502,如下所示:
SQL> insert into test values(1,'A');
insert into test values(1,'A')
*
ERROR at line 1:
ORA-01502: index 'U1.PK_TEST_ID' or partition of such index is in unusable state
如果這時我們刪除索引,也會報錯,提示有約束正在使用該索引,而不允許刪除。
SQL> drop index pk_test_id;
drop index pk_test_id
*
ERROR at line 1:
ORA-02429: cannot drop index used for enforcement of unique/primary key
從這兩個現象,也證明主鍵約束是通過相應列上的索引來配合完成的。
至此,我們對第一種創建約束和索引的方法做一個總結:當主鍵約束的索引為創建主鍵約束時數據庫自動創建的話,則關閉或刪除約束,會自動刪除相應的索引;而關閉相應的索引,雖然不會影響主鍵的狀態,但此時向表中插入數據會報錯(刪除數據,以及對主鍵列的更新也會報錯);而嘗試刪除該索引時,也會報錯,而不允許刪除該索引。
二、創建主鍵約束時,指定相應的索引的方法。
在創建主鍵約束時,我們也可以指定索引。方法如下:
SQL> drop table test purge;
Table dropped.
SQL> create table test (id number,c1 varchar2(8));
Table created.
SQL> alter table test add constraint pk_test_id primary key (id) using index (create index ind_test_id on test(id));
Table altered.
前兩條SQL是重建測試環境,以避免前面測試的影響。最后一條SQL則是在ID列上指定了主鍵約束,同時指定創建了在該列上的非唯一索引。
我們通過相關約束和索引視圖來查看一下:
SQL> ?select constraint_name,constraint_type,table_name,status from user_constraints where table_name='TEST';
CONSTRAINT_NAME CO TABLE_NAME ? ?STATUS
--------------- -- --------------- ----------------
PK_TEST_ID ?P ?TEST ? ? ENABLED
SQL> select index_name,uniqueness,table_name,status from user_indexes where table_name='TEST';
INDEX_NAME ?UNIQUENESS ? ? TABLE_NAME ? ? ? STATUS
--------------- ------------------ --------------- ----------------
IND_TEST_ID NONUNIQUE ? ? ?TEST ? ? ? ?VALID
注意最后一條索引信息中索引的名稱及唯一性與前面自動創建主鍵索引時的區別。這說明,非唯一索引,也可以用于配合完成主鍵約束。
如前測試,我們嘗試把主鍵約束關閉或刪除,看看是什么情況?
SQL> alter table test disable constraint pk_test_id;
Table altered.
SQL> select constraint_name,constraint_type,table_name,status from user_constraints where table_name='TEST';
CONSTRAINT_NAME CO TABLE_NAME ? ?STATUS
--------------- -- --------------- ----------------
PK_TEST_ID ?P ?TEST ? ? DISABLED
SQL> ?select index_name,uniqueness,table_name,status from user_indexes where table_name='TEST';
INDEX_NAME ?UNIQUENESS ? ? TABLE_NAME ? ? ? STATUS
--------------- ------------------ --------------- ----------------
IND_TEST_ID NONUNIQUE ? ? ?TEST ? ? ? ?VALID
可見,除了相應的主鍵約束失效外,索引并沒有受到影響。這與前邊自動創建主鍵索引的情況是不同的。
接下來,我們再嘗試關閉或刪除相應的索引,是否會影響到相應的主鍵約束。
SQL> alter table test enable constraint pk_test_id;
Table altered.
SQL> alter index ind_test_id unusable;
Index altered.
SQL> select constraint_name,constraint_type,table_name,status from user_constraints where table_name='TEST';
CONSTRAINT_NAME CO TABLE_NAME ? ?STATUS
--------------- -- --------------- ----------------
PK_TEST_ID ?P ?TEST ? ? ENABLED
SQL> select index_name,uniqueness,table_name,status from user_indexes where table_name='TEST';
INDEX_NAME ?UNIQUENESS ? ? TABLE_NAME ? ? ? STATUS
--------------- ------------------ --------------- ----------------
IND_TEST_ID NONUNIQUE ? ? ?TEST ? ? ? ?UNUSABLE
可見,關閉索引并沒有影響到相應主鍵約束的狀態。但是否也如前面測試那樣,不能插入數據呢?
SQL> insert into test values(1,'A');
insert into test values(1,'A')
*
ERROR at line 1:
ORA-01502: index 'U1.IND_TEST_ID' or partition of such index is in unusable state
果然,當主鍵約束所依賴的索引不可用時,數據的插入會報錯(刪除數據,以及對主鍵列的更新也會報錯);而嘗試刪除該索引時,也會報錯,而不允許刪除該索引。這一點和前面測試的情況是相同的。
SQL> drop index ind_test_id;
drop index ind_test_id
*
ERROR at line 1:
ORA-02429: cannot drop index used for enforcement of unique/primary key
三、創建主鍵約束時,已經在相應的主鍵列上存在索引時的情況
如果表TEST中已經存在了一個ID列上的索引,然后我再在ID列上創建主鍵約束,又是會是什么情況呢?
和前面一樣,我們先重置測試環境。
SQL> drop table test purge;
Table dropped.
SQL> create table test (id number,c1 varchar2(8));
Table created.
然后,我們先創建一個ID列上的索引。
SQL> create index ind_test_id on test(id);
Index created.
接著,我們在ID列上創建主鍵約束。
SQL> alter table test add constraint pk_test_id primary key (id);
Table altered.
查看約束和索引的情況:
SQL> select constraint_name,constraint_type,table_name,status from user_constraints where table_name='TEST';
CONSTRAINT_NAME CO TABLE_NAME ? ?STATUS
--------------- -- --------------- ----------------
PK_TEST_ID ?P ?TEST ? ? ENABLED
SQL> select index_name,uniqueness,table_name,status from user_indexes where table_name='TEST';
INDEX_NAME ?UNIQUENESS ? ? TABLE_NAME ? ? ? STATUS
--------------- ------------------ --------------- ----------------
IND_TEST_ID NONUNIQUE ? ? ?TEST ? ? ? ?VALID
我們可以看到,這次創建主鍵約束時,自動選用了主鍵列上已經存在的索引,并沒有像測試一中那樣,去創建一個與主鍵同名的唯一索引。
我們繼續測試關閉或刪除約束,是否會影響索引?
SQL> alter table test disable constraint pk_test_id;
Table altered.
SQL> select constraint_name,constraint_type,table_name,status from user_constraints where table_name='TEST';
CONSTRAINT_NAME CO TABLE_NAME ? ?STATUS
--------------- -- --------------- ----------------
PK_TEST_ID ?P ?TEST ? ? DISABLED
SQL> select index_name,uniqueness,table_name,status from user_indexes where table_name='TEST';
INDEX_NAME ?UNIQUENESS ? ? TABLE_NAME ? ? ? STATUS
--------------- ------------------ --------------- ----------------
IND_TEST_ID NONUNIQUE ? ? ?TEST ? ? ? ?VALID
發現索引并不受影響。
繼續測試關閉或刪除索引對主鍵約束的影響。
SQL> alter table test enable constraint pk_test_id;
Table altered.
SQL> ?alter index ind_test_id unusable;
Index altered.
SQL> ?select constraint_name,constraint_type,table_name,status from user_constraints where table_name='TEST';
CONSTRAINT_NAME CO TABLE_NAME ? ?STATUS
--------------- -- --------------- ----------------
PK_TEST_ID ?P ?TEST ? ? ENABLED
SQL> select index_name,uniqueness,table_name,status from user_indexes where table_name='TEST';
INDEX_NAME ?UNIQUENESS ? ? TABLE_NAME ? ? ? STATUS
--------------- ------------------ --------------- ----------------
IND_TEST_ID NONUNIQUE ? ? ?TEST ? ? ? ?UNUSABLE
SQL> ?insert into test values(1,'A');
insert into test values(1,'A')
*
ERROR at line 1:
ORA-01502: index 'U1.IND_TEST_ID' or partition of such index is in unusable state
SQL> drop index ind_test_id;
drop index ind_test_id
*
ERROR at line 1:
ORA-02429: cannot drop index used for enforcement of unique/primary key
和此前的測試完全一樣,將主鍵約束所依賴的索引關閉并不會影響主鍵約束的狀態,但修改數據(包括增刪改操作,其中修改特指對主鍵列的修改)是不被允許的。同樣,刪除索引,也是不被允許的。
至此,我們把前述三大測試總結一下:
1、對于創建主鍵約束時自動生成的同名唯一性索引的情況:
關閉或刪除主鍵約束,相應的索引會被刪除。
2、對于創建主鍵約束時,使用了非自動創建的索引的情況(在創建主鍵約束的SQL中指定創建索引或創建主鍵約束時,主鍵列上已有索引。):
關閉或刪除主鍵約束,相應的索引并不會被刪除,索引狀態也不受影響。
3、在任何一種情況下,關閉主鍵約束所依賴的索引,都會引起數據插入、刪除以及對主鍵列更新操作的報錯。
4、在任何一種情況下,刪除主鍵約束所依賴的索引,是不被允許的。
注意:
此外,有一個特例。即,當我們使用第二種方法,即在創建主鍵約束的同時,使用USING INDEX子句來創建了一個唯一索引時,比如:
alter table test add constraint pk_test_id primary key (id) using index (create unique index ind_test_id_uni on test(id));
如果這時,我關閉或刪除主鍵約束,則該索引會被自動刪除。而當我們恢復主鍵約束時,數據庫會自動創建一個與主鍵同名的唯一性索引。另外,當我們關閉手工創建的唯一索引或刪除它時,情況與前述的內容是一樣的。
來自 “ ITPUB博客 ” ,鏈接:http://blog.itpub.net/22207394/viewspace-2080449/,如需轉載,請注明出處,否則將追究法律責任。
總結
以上是生活随笔為你收集整理的oracle 主键约束重名,主键及主键索引的关系及相互影响的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python sympy安装_SymPy
- 下一篇: 谷歌浏览器外贸版_针对谷歌SEO,你有哪