思考兩個問題:
問題一:我們有兩個表,乙個表(department)存放的是部門的資訊,例如部門id,部門名稱等;另乙個表是員工表(staff),員工表裡面肯定要存放每個員工所在的部門。
那問題來了,如果我們這個時候刪除了部門表中的某條記錄,在staff表中會發生什麼?
問題二:是否有必要給外來鍵加索引。
為了解答上面的問題,讓我們先來回顧一下什麼是參照完整性。其實,理解了第乙個問題即參照完整性問題,第二個問題就迎刃而解了。
我們常常希望保證在乙個關係中給定屬性集上的取值也在另乙個關係的特定屬性集的取值中出現。這種情況稱為參照完整性(referential integrity)
下面直接給出測試過程:
建立測試表並插入測試資料
-- 部門表
create table department (
dept_id number(16),
dept_name varchar2(32),
primary key(dept_id)
);-- 員工表
create table staff (
user_id number(16),
user_name varchar2(32),
dept_id number(16),
primary key(user_id),
foreign key(dept_id) references department(dept_id)
--另一種寫法,可以給這個約束命名,而不使用系統預設名字:constraint fk_dept_id foreign key (dept_id) references department(dept_id)
--自己命名比較容易管理
);插入測試資料
insert into department (dept_id, dept_name) values (1, '技術部');
insert into department (dept_id, dept_name) values (2, '產品部');
insert into department (dept_id, dept_name) values (3, '測試部');
insert into staff (user_id, user_name, dept_id) values (1, '花花', 1);
insert into staff (user_id, user_name, dept_id) values (2, '小明', 1);
insert into staff (user_id, user_name, dept_id) values (3, '小常', 2);
insert into staff (user_id, user_name, dept_id) values (4, '張寶', 2);
insert into staff (user_id, user_name, dept_id) values (5, '趙勝', 2);
insert into staff (user_id, user_name, dept_id) values (6, '王五', 2);
insert into staff (user_id, user_name, dept_id) values (7, '星兒', 3);
進行參照完整性測試:
1、在從表中插入一條主表不存在的外來鍵資料
insert into staff (user_id, user_name, dept_id) values (8, '***xx', 4);
--error : ora-02291: integrity constraint (wlmedical.sys_c0039797) violated - parent key not found
--翻譯:違反完整性約束(wlmedical.sys_c0039797) -
2、刪除主表中一條記錄,且該鍵值在從表外來鍵中存在
delete from department where dept_id=1;
--error : ora-02292: integrity constraint (wlmedical.sys_c0039797) violated - child record found
--翻譯:違反完整性約束(wlmedical.sys_c0039797) - 有子記錄存在
3、更新主表記錄,且該鍵值在從表外來鍵中存在
update department set dept_id=4 where dept_id=1;
--error : ora-02292: integrity constraint (wlmedical.sys_c0039797) violated - child record found
--翻譯:違反完整性約束(wlmedical.sys_c0039797) - 有子記錄存在
由上操作可以看出,設定了外來鍵以後,對主表進行操作都會去從表檢查是否會違反參照完整性約束,所以我們可以給外來鍵新增索引以加快檢查速度;
同時,進行連線查詢的時候速度也會加快。故:給外來鍵加索引還是很有必要的。
參照完整性擴充套件:
當我們違反了參照完整性約束時,通常的處理(系統預設)是拒絕執行導致完整性破壞的操作(即進行更新操作的事務被回滾)。
當然,在foreign key子句中可以指明:如果被參照關係上的刪除或更新動作違反了約束,
那麼系統必須採取一些步驟通過修改參照關係中的元祖來恢復完整性約束,而不是拒絕這樣的操作。
接著剛才的測試資料繼續,
-- 首先刪除外來鍵
alter table staff drop constraint fk_dept_id sys_c0039797;
-- 重新宣告外來鍵,新增 級聯刪除、級聯更新屬性
這是資料庫外來鍵定義的乙個可選項,用來設定當主鍵表中的被參考列的資料發生變化時,外來鍵表中響應欄位的變換規則的。update 則是主鍵表中被參考字段的值更新,delete是指在主鍵表中刪除一條記錄:
on update 和 on delete 後面可以跟的詞語有四個
no action , set null , set default ,cascade
no action 表示 不做任何操作,
set null 表示在外鍵表中將相應字段設定為null
set default 表示設定為預設值
cascade 表示級聯操作,就是說,如果主鍵表中被參考字段更新,外來鍵表中也更新,主鍵表中的記錄被刪除,外來鍵表中改行也相應刪除
-- mysql 可以:
alter table staff add constraint fk_dept_id foreign key (dept_id) references department4(dept_id) on delete cascade on update cascade;
-- oracle:
alter table staff
add constraint fk_dept_id
foreign key (dept_id)
references department(dept_id)
on delete cascade ;
-- 檢視當前表的索引(oracle)
select * from user_indexes where table_name='staff';
-- 檢視當前表的索引(mysql)
show index from staff;
注:oracle中不支援級聯更新,因為oracle認為,作為外來鍵的一般都是主表的主鍵,通常,主鍵是常量是不應該有update的,任何的主鍵update都是bad practice。
如果出現 更新primary key的情況,那麼說明設計有問題,primary key肯定不是真正應該設定的primary key而是surrogate key,完全就是設計失誤。bad design 。
所以oracle這樣設計是有其道理的。
oracle 中可以使用觸發器 或者寫儲存過程,實現級聯更新。
-- 設定了級聯刪除以後,再刪除主表中的資料,則從表的對應的記錄也會被刪除
delete from department where dept_id=3;
select * from department; -- 剩餘 dept_id 1 2
select * from staff; -- dept_id為3的記錄被刪掉了。
總結:1、由於有了外來鍵聲名相關聯的on delete cascade子句,如果刪除department中的元祖導致了此參照完整性約束被違反,
則刪除並不被系統拒絕,而是對staff關係作聯機刪除,即刪除參照了被刪除系的元祖。類似的,on update cascade會在更新時同步進行參照關係中元祖的更新。
sql還允許foreign key子句指明除了cascade以外的其他動作,如果約束被違反,可將參考與置為null(用set null代替 cascade),或者置為預設值(set default)。
但是,一般來說,我們習慣的用法是,不允許刪除。如果實在要刪除,我覺得應該開發者自己寫**進行備份然後刪除,這樣也方便日後查詢、追蹤、留痕等相關操作。
2、回歸主題,索引,從以上可以看出,設定外來鍵以後 主表、從表之間是有級聯關係的,操作(更新、刪除)主表中的資料的時候系統會自動掃瞄從表中的資料,如果外來鍵有了索引肯定掃瞄會加快很多,
還有我們平時查詢從表記錄的時候也會連線主表,
所以,綜上,我們應該給從表的外來鍵設定索引,以加快對主表的更新、刪除操作,加快從表連線查詢速度。
mysql 參照完整性 mysql參照完整性
該樓層疑似違規已被系統摺疊 隱藏此樓檢視此樓 mysql支援資料庫的參照完整性約束嗎?有四個表 表一的主鍵是的表二外鍵 表二的主鍵是表三的外來鍵 表三的主鍵是表四的外來鍵 請問 如果 刪除表一 表2 3 4 會自動刪除嗎?從 3.23.43b 開始 innodb 支援外來鍵約束特性。innodb 表...
mysql 參照完整性 mysql參照完整性
該樓層疑似違規已被系統摺疊 隱藏此樓檢視此樓 mysql支援資料庫的參照完整性約束嗎?有四個表 表一的主鍵是的表二外鍵 表二的主鍵是表三的外來鍵 表三的主鍵是表四的外來鍵 請問 如果 刪除表一 表2 3 4 會自動刪除嗎?從 3.23.43b 開始 innodb 支援外來鍵約束特性。innodb 表...
MySQL的外來鍵和參照完整性
一 參照完整性 referential integrity 和外來鍵 foreign key 參照完整性 referential integrity 是用於約定兩個關係之間的聯絡,理論上規定 若m是關係s中的一屬性組,且m是另一關係z的主關鍵字,則稱m為關係s對應關係z的外關鍵字。若m是關係s的外關...