Oracle如何管理帶約束的B樹索引
管理帶約束的B樹索引
B樹索引與主鍵和唯一鍵約束是分不開的。這是因為Oracle使用索引來強制執行主鍵和唯一鍵約束。若沒有相關聯的B樹索引,將不能啟用主鍵或唯一約束。
在建立主鍵或唯一鍵約束時,你可以選擇讓Oracle自動建立相應索引。在這種情況下,如果刪除或禁用約束,Oracle也將自動刪除相應的索引。
單獨建立索引和約束也是可以的。當單獨建立索引和約束時,允許刪了或禁用約束,而不會自動刪除相應的索引。如果有大量資料需要處理,你可能希望禁用約束,而不刪除相應索引。
因為在定義外來鍵約束時,Oracle不會自動建立索引,所以必須手動在與外來鍵約束相關的列上建立索引。在大多數情況下,在外來鍵列上建立B樹索引是有益的,因為它有助於避免鎖定問題,並提高透過主鍵和外來鍵列連線父/子表的查詢的效能。
1 在主鍵列上建立B樹索引
主鍵約束保證在一列(或列的組合)中的值可用於唯一標識表內的記錄。每個表只能有一個主鍵約束。主鍵約束不能包含空值。主鍵約束可以被看做是唯一(unique)約束和非空(NOT NULL)約束的結合。為每個表建立主鍵索引有如下幾個很好的理由。
.強制執行了主鍵列在表內必須是唯一的這一業務需求。是的,在某些情況下,可能有一個不需要主鍵的表(比如日誌表),但在大多數情況下,主鍵對每個表都是必需的。
.主鍵中的許多列,在訪問應用程式的查詢的where子句中被頻繁使用。這些列上的索引將會改善查詢的效能。
.除非已定義父表主鍵或唯一鍵約束,否則Oracle將不允許建立子表的外來鍵約束。因此,如果需要外來鍵約束,就必須使用主鍵或唯一鍵約束。
對任何啟用的主鍵,Oracle都需要一個與之對應的索引。有幾種技術可用來建立主鍵約束及其對應的索引。
.首先建立表。然後在單獨的alter table語句中新增主鍵約束。alter table語句同時建立了主鍵約束和索引。
.在create table 語句中內聯(與列一起)或在單獨的部分中指定主鍵約束。
.首先建立表,然後使用create index語句建立包含主鍵列的索引,最後使用alter table ... add constraint語句新增主鍵約束。
1.1.使用alter table來建立主鍵約束和索引
下面介紹的這種技術是建立主鍵約束和相關聯的索引最可取的方法。這種方法允許對錶的建立與約束和索引的定義分別進行管理。如果你使用的應用程式包含數千個表,約束和索引,那麼將建立表與建立相應的約束和索引分開,可以使用管理和診斷安裝問題變得更容易。這不是死板的規定,相反,它是從診斷問題演變而來的一種偏好。
在這個例子中,表和主鍵約束是分別建立的。首先,建立表時沒有定義任何約束。
SQL> create table cust2 2 ( 3 cust_id number, 4 first_name varchar2(200), 5 last_name varchar2(200) 6 ) tablespace reporting_data; Table created.
然後新增主鍵約束
SQL> alter table cust2 add constraint cust2_pk primary key(cust_id) using index tablespace reporting_index; Table altered.
此程式碼示例使用alter table ... add constraint語句同時建立主鍵約束和唯一索引。約束和索引都被命名為CUSTS_PK。
1.2.使用create table建立主鍵約束和索引
另一種常見的方法是用create table語句建立主鍵約束和索引。可以內聯(和列一起)直接指定一個約束。這種方法的優點是簡單。如果在開發或測試環境中進行試驗,這種方法是快速且有效的。但這種方法也有一個缺點,它不允許在多個列上定義主鍵。例如:
SQL> create table cust3 2 ( 3 cust_id number primary key, 4 first_name varchar2(30), 5 last_name varchar2(30) 6 ) 7 tablespace reporting_data; Table created. SQL> insert into cust3 values(1,'jing','yong'); 1 row created. SQL> commit; Commit complete. SQL> select a.segment_name,a.segment_type,a.extents,a.bytes from user_segments a,user_indexes b where a.segment_name=b.index_name and b.table_name in('CUST3'); SEGMENT_NAME SEGMENT_TYPE EXTENTS BYTES -------------------------------------------------------------------------------------------------------------------------------- ------------------ ---------- ---------- SYS_C0023486 INDEX 1 1048576
在這段程式碼中,Oracle建立了主鍵約束和相應的唯一索引。Oracle自動生成像SYS_C0023486這樣的隨機名稱(約束和索引也被賦予了相同的名稱)。
如果想要明確地對約束和索引提供名稱,就可以執行下面這樣的語句:
SQL> create table cust4 2 ( 3 cust_id number constraint cust4_pk primary key, 4 first_name varchar2(30), 5 last_name varchar2(30) 6 ) 7 tablespace reporting_data; Table created. SQL> insert into cust4 values(1,'jing','yong'); 1 row created. SQL> commit; Commit complete. SQL> select a.segment_name,a.segment_type,a.extents,a.bytes from user_segments a,user_indexes b where a.segment_name=b.index_name and b.table_name in('CUST4'); SEGMENT_NAME SEGMENT_TYPE EXTENTS BYTES -------------------------------------------------------------------------------------------------------------------------------- ------------------ ---------- ---------- CUST4_PK INDEX 1 1048576
也可以指定放置索引的表空間,如下所示:
SQL> create table cust5 2 ( 3 cust_id number constraint cust5_pk primary key using index tablespace reporting_index, 4 first_name varchar2(30), 5 last_name varchar2(30) 6 ) 7 tablespace reporting_data; Table created.
還可以在create table語句單獨的部分中定義主鍵約束(不和列在一起)。下面是在單獨的部分定義主鍵約束的例子:
SQL> create table cust6 2 ( 3 cust_id number, 4 first_name varchar2(30), 5 last_name varchar2(30), 6 constraint cust6_pk primary key(cust_id) using index tablespace reporting_index 7 ) 8 tablespace reporting_data; Table created.
這種技術被稱為外聯(out-of-line),因為約束的宣告與列定義之間是用逗號隔開的。該做法與內聯的方法相比,具有可以為主鍵指定多列的優勢。
1.3.分別建立B-tree索引和主鍵約束
還可以首先建立索引,然後改變表以應用主鍵約束。為了保持這個例子的完整性,這裡也顯示了create table語句。
SQL> create table cust7 2 ( 3 cust_id number, 4 first_name varchar2(30), 5 last_name varchar2(30) 6 ) 7 tablespace reporting_data; Table created. SQL> create unique index cust7_pk on cust7(cust_id) tablespace reporting_index; Index created. SQL> alter table cust7 add constraint cust7_pk primary key(cust_id); Table altered.
這種方法的優點是,可以獨立於索引刪除或禁用主鍵約束。在大型資料庫環境中,出於資料載入時效能方面的原因,有時可能想要刪除或禁用約束。有時可能需要能刪除約束,但不刪除索引的靈活性。在大型資料庫環境中,重建索引會花費很長的時間並消耗大量的系統資源。
另一種稍微有些牽強的情況是,有可能建立一個與主鍵約束定義的列不同的列的索引。例如:
SQL> create table cust8 2 ( 3 cust_id number, 4 first_name varchar2(30), 5 last_name varchar2(30) 6 ) 7 tablespace reporting_data; Table created. SQL> create index cust8_pk on cust8(cust_id,first_name,last_name) tablespace reporting_index; Index created. SQL> alter table cust8 add constraint cust8_pk primary key(cust_id); Table altered.
建議不要建立與約束列不同的列的主鍵索引,但這麼做是可以的。你應該知道有這種情況,避免在診斷問題時感到困惑。
1.4.檢視主鍵約束和索引的詳細資訊
用如下語句可以確認某個索引的詳細資訊:
SQL> select index_name,index_type,uniqueness from user_indexes where table_name='CUST7'; INDEX_NAME INDEX_TYPE UNIQUENES -------------------------------------------------------------------------------------------------------------------------------- --------------------------- --------- CUST7_PK NORMAL UNIQUE
輸出如上所示,為了驗證約束的資訊,可執行如下查詢:
SQL> select constraint_name,constraint_type from user_constraints where table_name='CUST7'; CONSTRAINT_NAME CONSTRAINT_TYPE -------------------------------------------------------------------------------------------------------------------------------- ------------------------------ CUST7_PK P
1.5.刪除主鍵約束和索引
建立主鍵約束時自動建立的索引不能直接刪除。在這種情況下,如果像下面這樣直接刪除索引:
SQL> drop index cust4_pk;
就會收到如下錯誤資訊:
drop index cust4_pk * ERROR at line 1: ORA-02429: cannot drop index used for enforcement of unique/primary key
要刪除索引,必須首先刪除或禁用主鍵約束。例如,下面的語句將刪除建立約束時自動建立的索引:
SQL> alter table cust4 disable constraint cust4_pk; Table altered. SQL> alter table cust4 drop constraint cust4_pk; Table altered.
或者
SQL> alter table cust4 drop primary key; Table altered.
在刪除或禁用主鍵約束時,可以選擇不刪除相關索引。可以使用drop/disable constraint子句的keep index子句來保留索引。例如:
SQL> alter table cust4 drop constraint cust4_pk keep index; Table altered.
此程式碼指示Oracle刪除約束,但保留索引。如果要處理的是很大的表,那麼出於載入或操縱資料時效能方面的原因,可能要禁用或刪除約束,而非索引,因為刪除與一個大表相關聯的索引後,可能需要相當長的時間和大量資源來重新建立它。
要注意的另一個方面是,如果主鍵或唯一鍵被已啟用的外來鍵引用,而試圖刪除父表上的約束,如下所示:
SQL> alter table cust1 drop primary key;
就會收到如下錯誤資訊:
alter table cust1 drop primary key * ERROR at line 1: ORA-02273: this unique/primary key is referenced by some foreign keys
在這種情況下,需要先刪除或禁用引用的外來鍵,或使用cascade子句在主鍵約束已經被刪除或禁用時,自動刪除外來鍵約束。例如:
SQL>alter table cust1 drop constraint cust1_pk cascade; SQL>alter table cust1 disable constraint cust1_pk cascade; SQL>alter table cust1 drop primary key cascade;
級聯刪除約束只刪除了所有依賴外來鍵的約束,但不從子表中刪除任何資料。
2 在唯一鍵列上建立B樹索引
唯一鍵約束的主要目的是強制地不屬於主鍵一部分的列的唯一性。如果有非主鍵列在一個表中是唯一的這種業務需求,那麼應該使用唯一約束。例如,你可能有定義在客戶表的cust_id列上的主鍵,但可能還需要一個last_name和first_name列的組合上的唯一鍵約束。
唯一鍵與主鍵有兩方面的差別。首先,唯一鍵可以包含NULL值,其次每個表可以定義多個唯一鍵(而每個表只能定義一個主鍵)。
如果需要為某個列建立唯一約束,那麼可以透過下列幾種不同的方式來實現這一需求。
.使用alter table語句來建立一個唯一約束。這將自動建立一個唯一的B樹索引。
.使用create table語句來建立一個唯一約束。這也將自動建立一個唯一的B樹索引。
.分別建立B樹索引和約束。如果想要在禁用或刪除約束時分別管理索引和約束,那麼可以使用這種方法。
.只建立唯一B樹索引,而不費心去建立唯一鍵約束。如果索引中的列不能被子表的外來鍵引用,那麼可以使用這種方法。
2.1.使用alter table來建立唯一約束和索引
這種方法是我們啟用唯一鍵約束並建立相應索引的首選方法。正如在主鍵約束和索引部分中提到的,將建立表的語句與建立約束和索引的語句分離,往往更容易診斷安裝問題。
下面的示例演示如何建立一個表,然後在非主鍵列上新增一個唯一鍵約束。
SQL> create table cust9 2 ( 3 cust_id number, 4 first_name varchar2(30), 5 last_name varchar2(30) 6 ) 7 tablespace reporting_data; Table created.
接下來,使用alter table語句在cust表的last_name和first_name列的組合上建立一個名為cust9_ux1的唯一約束。
SQL> alter table cust9 add constraint cust9_uk1 unique(last_name,first_name) using index tablespace reporting_index; Table altered.
此語句建立了該唯一約束。此外,Oracle會自動建立一個具有相同名稱的相關索引。
2.2.使用create table建立唯一約束和索引
使用create table方法的優點在於,它簡單且可以把索引和約束的建立封裝在一個語句中。在用create table語句定義唯一約束時,它可以用內網聯方式,也可以用外聯方式來定義。
第一個例子顯示瞭如何在一個列上內聯地建立唯一鍵約束和索引。由於內聯唯一鍵約束只可以定義在列上,所以我們新增了SSN列,它以內聯內式定義了唯一鍵約束。
SQL> create table cust10 2 ( 3 cust_id number constraint cust10_pk primary key using index tablespace reporting_index, 4 first_name varchar2(30), 5 last_name varchar2(30), 6 ssn varchar2(15) constraint cust10_uk1 unique using index tablespace reporting_index 7 ) 8 tablespace reporting_data; Table created.
下一個例子使用外聯技術在first_name和last_name列的組合上建立了一個唯一約束:
SQL> create table cust11 2 ( 3 cust_id number constraint cust11_pk primary key using index tablespace reporting_index, 4 first_name varchar2(30), 5 last_name varchar2(30), 6 ssn varchar2(15), 7 constraint cust11_uk1 unique(first_name,last_name) using index tablespace reporting_index 8 ) 9 tablespace reporting_data; Table created.
外聯方式的定義具有允許在多列上建立一個唯一鍵約束的優勢。
2.3.分別建立B樹索引和唯一鍵約束
如果需要分別管理索引和約束,那麼可以先建立索引,然後再建立約束。例如:
SQL> create table cust12 2 ( 3 cust_id number, 4 first_name varchar2(30), 5 last_name varchar2(30) 6 ) 7 tablespace reporting_data; Table created. SQL> create unique index cust12_uk1 on cust12(first_name,last_name) tablespace reporting_index; Index created. SQL> alter table cust12 add constraint cust12_uk1 unique(first_name,last_name); Table altered.
分別建立索引和約束的好處是,可以在不刪除底層索引的情況下刪了或禁用約束。在處理大量資料時,可考慮使用這種方法。如果你有任何理由需要禁用約束,然後重新啟用它,就可以這樣做而不刪除索引(因為重新建立大索引可能需要很長一段時間)。
2.4.只建立唯一索引
還可以只建立唯一索引而不新增唯一約束。如果你從來沒有計劃用外來鍵引用一個唯一鍵,那麼只建立一個唯一索引而不定義唯一約束也是可以的。下面是建立一個無關聯約束的唯一索引的例子:
SQL> create table cust13 2 ( 3 cust_id number, 4 first_name varchar2(30), 5 last_name varchar2(30) 6 ) 7 tablespace reporting_data; Table created. SQL> create unique index cust13_uk1 on cust13(first_name,last_name) tablespace reporting_index; Index created.
在用上述語句明確地建立唯一索引時,Oracle雖然建立了一個唯一索引,但卻沒有在dba/all/user_constraints中為約束新增條目。為什麼這很重要呢?,考慮這種情況:
SQL> insert into cust13 values(1,'JAMES','STARK'); 1 row created. SQL> insert into cust13 values(2,'JAMES','STARK');
下面是被丟擲的相應錯誤訊息提示:
insert into cust13 values(2,'JAMES','STARK') * ERROR at line 1: ORA-00001: unique constraint (JY.CUST13_UK1) violated
如果讓你來診斷這個問題的話,你首先會檢查的地方是dba_constraints,你會按錯誤訊息中顯示的名稱在其中查詢一個約束。然而,沒有查到任何資訊。
SQL> select constraint_name from dba_constraints where constraint_name='CUST13_UK1'; no rows selected
沒有相關記錄可能會使用人困惑:向表中插入資料時,丟擲的錯誤訊息已經表明違反了唯一約束,但在與約束相關的資料字典檢視中卻沒有它的資訊。在這種情況下,必須在dba_indexes中檢視已經建立的唯一索引的詳細資訊。例如:
SQL> select index_name,uniqueness from dba_indexes where index_name='CUST13_UK1'; INDEX_NAME UNIQUENES -------------------------------------------------- --------- CUST13_UK1 UNIQUE
如果你希望能夠使用與約束相關的資料字典檢視來報告唯一鍵約束,就應該也定義一個約束。
2.5.刪除唯一鍵約束和索引
如果索引是建立唯一鍵約束時自動建立的,那麼不能直接刪除該索引。在這種情況下,必須刪除或禁用唯一鍵約束,而相關的索引會自動被刪除。例如:
SQL> drop index cust11_uk1; drop index cust11_uk1 * ERROR at line 1: ORA-02429: cannot drop index used for enforcement of unique/primary key SQL>alter table cust11 drop constraint cust11_uk1;
這行語句同時刪除約束和索引。如果想保留索引,那麼可以指定keep index子句。
SQL>alter table cust drop constraint cust11_uk1 keep index;
如果分別建立索引和唯一鍵約束,或者如果沒有唯一鍵約束與唯一索引相關聯,那麼可以直接刪除該索引。
3 索引外來鍵列
外來鍵約束確保插入資料到子表時,相應的父表記錄存在。這是一個保證資料符合父/子業務關係規則的機制。外來鍵也被稱為參照完整性約束。
不同於主鍵和唯一鍵約束,Oracle不會自動建立外來鍵列上的索引。因此,必須在定義為外來鍵約束的列的基礎上手動建立一個外來鍵索引。在大多數情況下,應該在與外來鍵關聯的列上建立索引。這裡有兩個原因。.Oracle經常可以利用外來鍵列上的索引,來改善使用外來鍵列來連線父表和子表的查詢效能。.如果外來鍵列上沒有B樹索引存在,在往子表插入資料或從子表刪除資料時,它會鎖定父表中的所有行。對於頻繁修改父表和子表的應用程式,這將導致鎖定和死鎖問題。
首先討論如何在一個外來鍵列上建立B樹索引,然後再介紹用來檢測未被索引的外來鍵列的一些技巧。
3.1.在外來鍵列上實現索引
假設有這樣的需求:必須為address1表的每條記錄分配cust14表中存在的一個相應cust_id列。為了強制執行這種關係,在address1表上建立如下外來鍵約束:
SQL> create table cust14( 2 cust_id number, 3 last_name varchar2(30), 4 first_name varchar2(30) 5 ) 6 tablespace reporting_data; Table created. SQL> create table address1( 2 address_id number, 3 cust_id number, 4 street varchar2(30), 5 city varchar2(30), 6 state varchar2(30) 7 ) 8 tablespace reporting_data; Table created. SQL> alter table address1 add constraint addr1_fk1 foreign key(cust_id) references cust14(cust_id); alter table address1 add constraint addr1_fk1 foreign key(cust_id) references cust14(cust_id) * ERROR at line 1: ORA-02270: no matching unique or primary key for this column-list
注意,外來鍵列必須引用父表中定義了主鍵或唯一鍵約束的列。否則,就會收到錯誤提示資訊"ORA-02270: 此列列表無匹配的唯一鍵或主鍵"。
因為在連線cust14表和address1表時,外來鍵列被廣泛使用,且外來鍵列上的索引會提高效能,所以在這種情況下,必須手動建立一個索引。例如,在address1表的cust_id外來鍵列上建立普通的B樹索引。
SQL>create index addr1_fk1 on address1(cust_id);
索引名不必與外來鍵名稱相同。是否這樣做,只是一種個人喜好。我們覺得約束和相應的索引具有相同的名稱時,維護環境更容易。
建立索引時,如果不指定表空間名稱,Oracle會在使用者的預設表空間放置索引。一般情況下,最好明確指定該表的索引的存放位置。例如:
create index addr1_fk1 on address1(cust_id) tablespace reporting_index;
注意,外來鍵列上的索引,並不一定是B樹型別的。在資料倉儲環境中,經常在星型模式的事實表的外來鍵列上使用點陣圖索引。與B樹索引不同,外來鍵列上的點陣圖索引不能解決父/子表鎖定的問題。使用星型模式的應用程式通常不從事實表刪除或修改子記錄,因此在資料倉儲環境中,在外來鍵列上使用點陣圖索引,鎖定不是什麼問題。
3.2.確定外來鍵列是否已經被索引
如果你從頭開始建立一個應用程式,那麼建立程式程式碼,並確保每一個外來鍵約束都有相應的索引很容易。但是,如果你繼承了一個現成的資料庫,就需要審慎地檢查外來鍵列是否已經被索引。
你可以使用資料字典檢視來驗證,外來鍵約束的所有列上是否有相應的索引。其基本思路是檢查每個外來鍵約束,看它是否有一個相應的索引,這個任務並不像一開始看上去那麼簡單。用下面的查詢作為例子,它可以用來指導你按正確的途徑入手:
SQL> col owner for a30 SQL> col cons_name for a30 SQL> col tab_name for a30 SQL> col cons_column for a30 SQL> col ind_column for a30 SQL> select distinct 2 a.owner owner, 3 a.constraint_name cons_name, 4 a.table_name tab_name, 5 b.column_name cons_column, 6 nvl(c.column_name,'***Check index***') ind_column 7 from dba_constraints a,dba_cons_columns b,dba_ind_columns c 8 where a.constraint_type='R' 9 and a.owner=UpPER('&&user_name') 10 and a.owner=b.owner 11 and a.constraint_name=b.constraint_name 12 and b.column_name=c.column_name(+) 13 and b.table_name=c.table_name(+) 14 and b.position=c.column_position(+) 15 order by tab_name,ind_column; old 9: and a.owner=UpPER('&&user_name') new 9: and a.owner=UpPER('JY') OWNER CONS_NAME TAB_NAME CONS_COLUMN IND_COLUMN ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ JY ADDR_FK1 ADDRESS CUST_ID CUST_ID
雖然此查詢簡單並易於理解,但它並不能在所有情況下都正確地報告出未索引的外來鍵。例如,在多列外來鍵的情況下,以不同於索引列的順序定義約束也不要緊,只要索引列在該索引中位於前面即可。換句話說,如果約束被定義為col1和col2,那麼定義一個先是col2,然後是col1的B樹索引也沒關係。
另一方面,使用B樹索引有助於避免鎖定的問題,但點陣圖索引卻做不到這點。在這種情況下,查詢還應該檢查索引型別。
在這些情況下,需要用更復雜的查詢來檢測與外來鍵列相關的索引問題。下面的例子是一個更復雜的查詢,它使用listagg分析函式來比較外來鍵約束列(作為字串返回一行)與相應的索引列:
這個查詢會先提示你輸入一個模式名稱,然後將顯示沒有相應的索引的外來鍵約束。此查詢還檢查了索引型別,點陣圖索引可以在外來鍵列上存在,但它不能防止鎖定問題。
SQL> select 2 case when ind.index_name is not null then 3 case when ind.index_type in('BITMAP') then 4 '** Bitmp idx **' 5 else 6 'indexed' 7 end 8 else 9 '** Check idx **' 10 end checker, 11 ind.index_type, 12 cons.owner,cons.table_name,ind.index_name,cons.constraint_name,cons.cols 13 from( select 14 c.owner,c.table_name,c.constraint_name, 15 listagg(cc.column_name,',') within group (order by cc.column_name) cols 16 from dba_constraints c,dba_cons_columns cc 17 where c.owner=cc.owner 18 and c.owner=UPPER('&&schema') 19 and c.constraint_name=cc.constraint_name 20 and c.constraint_type='R' 21 group by c.owner,c.table_name,c.constraint_name) cons 22 left outer join 23 (select 24 table_owner,table_name,index_name,index_type,cbr,listagg(column_name,',') within group (order by column_name) cols 25 from(select 26 ic.table_owner,ic.table_name,ic.index_name,ic.column_name,ic.column_position,i.index_type, 27 connect_by_root(ic.column_name) cbr 28 from dba_ind_columns ic,dba_indexes i 29 where ic.table_owner=UPPER('&&schema') 30 and ic.table_owner=i.table_owner 31 and ic.table_name=i.table_name 32 and ic.index_name=i.index_name 33 connect by prior ic.column_position-1=ic.column_position 34 and prior ic.index_name=ic.index_name) 35 group by table_owner,table_name,index_name,index_type,cbr) ind 36 on cons.cols=ind.cols 37 and cons.table_name=ind.table_name 38 and cons.owner=ind.table_owner 39 order by checker,cons.owner,cons.table_name; Enter value for schema: JY old 18: and c.owner=UPPER('&&schema') new 18: and c.owner=UPPER('JY') old 29: where ic.table_owner=UPPER('&&schema') new 29: where ic.table_owner=UPPER('JY') CHECKER INDEX_TYPE OWNER TABLE_NAME INDEX_NAME CONSTRAINT_NAME COLS ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ------------------------------ ** Check idx ** JY ADDRESS ADDR_FK1 CUST_ID
表鎖和外來鍵
下面用一個簡單的例子來演示外來鍵列沒有索引時的鎖定問題。
首先建立兩個表(dept和emp)並用一個外來鍵約束把它們關聯起來。
SQL> create table emp(emp_id number primary key,dept_id number); Table created. SQL> create table dept(dept_id number primary key); Table created. SQL> alter table emp add constraint emp_fk1 foreign key(dept_id) references dept(dept_id); Table altered.
插入資料
SQL> insert into dept values(10); 1 row created. SQL> insert into dept values(20); 1 row created. SQL> insert into dept values(30); 1 row created. SQL> insert into emp values(1,10); 1 row created. SQL> insert into emp values(2,20); 1 row created. SQL> insert into emp values(3,30); 1 row created. SQL> commit; Commit complete.
開啟兩個終端會話。在一個會話中,從子表刪除一條記錄,但不提交。
SQL> delete from emp where dept_id=10; 1 row deleted.
現在嘗試(在另一個會話裡)從父表中刪除一些不受子表刪除操作影響的資料。
SQL> delete from dept where dept_id=30;
對父表資料的刪除操作會掛起,直到子表的事務初步提交(或回滾)。如果子表中的外來鍵列上沒有常規的B樹索引,那麼任何時間嘗試往子表插入資料或刪除子表的資料時,它都會在父表上放置一個全表鎖,在子表的事務完成前,該全表鎖會一直阻止刪除或更新父表的資料。
回滾刪除子表資料的操作
SQL> rollback; Rollback complete.
當回滾刪除子表資料的操作後,刪除父表資料的操作報錯,因為違反完整性約束
SQL> delete from dept where dept_id=30; delete from dept where dept_id=30 * ERROR at line 1: ORA-02292: integrity constraint (JY.EMP_FK1) violated - child record found
現在額外建立一個子表外來鍵列上的索引,並再次執行前面的操作。
SQL> create index emp_fk1 on emp(dept_id); Index created.
再次執行刪除操作,刪除子表的資料
SQL> delete from emp where dept_id=10; 1 row deleted.
在另一個會話中刪除父表資料不會掛起會立即報違反完整性約束
SQL> delete from dept where dept_id=30; delete from dept where dept_id=30 * ERROR at line 1: ORA-02292: integrity constraint (JY.EMP_FK1) violated - child record found
這樣就能夠獨立地執行前面列出的兩個delete語句。當外來鍵列上有B樹索引時,如果從子表中刪除資料,Oracle將不會過分地鎖定父表中的所有行資料。
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/26015009/viewspace-2732702/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- Oracle如何建立B樹索引Oracle索引
- Oracle如何實現B樹索引Oracle索引
- Oracle中的B樹索引Oracle索引
- Oracle主鍵約束、唯一鍵約束、唯一索引的區別(轉)Oracle索引
- 查詢oracle表的資訊(表,欄位,約束,索引)Oracle索引
- Oracle約束Oracle
- oracle 約束Oracle
- Oracle - 約束、索引等相關常用操作語句Oracle索引
- oracle中的約束Oracle
- 教你如何成為Oracle 10g OCP - 第九章 物件管理(8) - 如何重建B樹索引Oracle 10g物件索引
- MySQL中的 UNIQUE約束和UNIQUE索引MySql索引
- 教你如何成為Oracle 10g OCP - 第九章 物件管理(7) - B樹索引的對於DELETE的管理Oracle 10g物件索引delete
- Oracle定義約束 外來鍵約束Oracle
- oracle的延遲約束Oracle
- 教你如何成為Oracle 10g OCP - 第九章 物件管理(6) - B樹索引的訪問Oracle 10g物件索引
- 建約束(Constraint)時隱式建立索引(Index)及先建立索引後建立約束的區別AI索引Index
- 用函式索引構造特殊的約束函式索引
- 【Mysql】InnoDB 中的 B+ 樹索引MySql索引
- B樹索引的內部結構索引
- 淺談MySQL的B樹索引與索引優化MySql索引優化
- oracle 約束詳解Oracle
- Oracle約束簡介Oracle
- oracle鍵約束控制Oracle
- 修改oracle的約束欄位Oracle
- 如何在ORACLE中修改表的約束條件啊Oracle
- Mysql InnoDB B+樹索引和雜湊索引的區別? MongoDB 為什麼使用B-樹?MySql索引MongoDB
- 搞懂MySQL InnoDB B+樹索引MySql索引
- 平衡樹索引(b-tree index)索引Index
- Windows系統如何批量結束工作管理員的程式樹?Windows
- Windows系統如何批次結束工作管理員的程序樹?Windows
- 【SQL】15 SQL 約束(Constraints)、NOT NULL 約束、UNIQUE 約束、PRIMARY KEY 約束、FOREIGN KEY 約束、CHECK 約束、DEFAULT約束SQLAINull
- oracle 註釋和約束Oracle
- 新增/刪除約束(Oracle)Oracle
- Oracle中檢視無效的物件、約束、觸發器和索引(Helloblock寫作)Oracle物件觸發器索引BloC
- oracle 約束的novalidate 應用Oracle
- B樹索引和點陣圖索引的結構介紹索引
- 專案管理的三重約束專案管理
- 解決資料庫的索引亂碼問題,先刪除外來鍵約束,再刪除主鍵約束及其索引資料庫索引