oracle為什麼盡量不要使用外來鍵的最好理解

2022-03-25 20:56:37 字數 1589 閱讀 4756

對於死鎖問題相信大家都是很頭疼的,為什麼不要使用外來鍵呢?最簡單的回答就是太容易產生死鎖了。

經過個人的測試,我發現外來鍵刪除的時候,是按照表會話的順序執行的,也就是說如果只有乙個事務,只要子表刪掉外來鍵表的項,外來鍵表就可以刪除,但是如果同時有多個事務,這就難說了,具體舉例子如下:

首先我們建立表並建立資料,順序執行如下**:

create

table t_p (id number

primary

key, name varchar2(30

));

create

table t_f (fid number, f_name varchar2(30), foreign

key (fid) references

t_p);

insert

into t_p values (1, 'a'

); insert

into t_f values (1, 'a'

); insert

into t_p values (2, 'b'

); insert

into t_f values (2, 'c'

); commit;

然後測試如下:我在本使用者下(c##bendiheli)和system下開啟兩個sql工作表:

其中在c##bendiheli記為sql1,system下記為sql2

如果程式的執行順序為:

1.sql1:delete t_f where fid = 2; 

2.sql2:delete c##bendiheli.t_f where fid = 1; 

3.sql1:delete t_p where id = 2; 

此時sql1等待,因為sql2未提交(這就是我理解的外來鍵表需要找會話,本會話可以繼續,如果有其他會話未提交,他就等待)

4.sql2:delete c##bendiheli.t_p where id = 1; 

此時sql2等待,因為sql1未提交

現在的程式sql1的事務等待sql2的提交,sql2的事務等待sql1的提交,完了,鎖住了。

至於本人理解外來鍵是按照會話尋找的原因是,即使我把2換成insert into c##bendiheli.t_f values(1,'duidu'),3仍然會等待,因為2沒提交

若我執行順序為如下,則可以,這樣就更能理解我的想法,就是外來鍵按照非本會話的會話順序執行

1.sql1:delete t_f where fid = 2; 

2.sql2:insert into c##bendiheli.t_f values(1,'duidu')

3.sql1:delete t_p where id = 2; 

此時sql1等

4.sql2:commit;

提交後sql1就不再等待

解決方案:外來鍵加索引

create

index ind_t_f_fid on t_f(fid);

個人理解,這樣就解決了外來鍵按照會話找連線表的,而是通過索引來找,這樣以來上方出現死鎖的程式就不再出現死鎖,因為這樣在本事務內,直接找索引即可。 

本文的理解借鑑於博主:

為什麼盡量不要使用eval函式和with關鍵字

編譯過程 分詞 詞法分析 解析 語法分析 生成 詞法作用域 定義在詞法階段的作用域 作用域 是一套規則,定義了引擎如何在作用域中通過識別符號名稱對變數進行查詢 作用域工作模型 詞法作用域 動態作用域 詞法化 編譯器工作的第一階段,即對 中的字元進行檢查。如果是有狀態的解析還會賦予單詞語義1.效能問題...

盡量不要使用FindWindow

盡量不用 findwindow 最近發現 se6和 se5程序共存時視窗名稱一樣引起的 bug。原因是我們經常使用 findwindow 來獲得視窗控制代碼,然後進行訊息通訊,這樣呼叫簡單,但增加了不同模組之間的依賴性,比如同時有兩個程序時,就可能會找錯視窗。而如果靠人去維護這個視窗名稱,在程式工程...

盡量不要使用可變引數

在某些情況下我們希望函式引數的個數可以根據實際需要來確定,所以c語言中就提供了一種長度不確定的引數,形如 c 語言也繼承了這一語言特性。在採用ansi標準形式時,引數個數可變的函式的原型是 typefuncname typepara1,typepara2,這種形式至少需要乙個普通的形式引數,後面的省...