為什么大多數互聯網公司不用外鍵約束


是否使用外鍵約束

【強制】不得使用外鍵與級聯,一切外鍵概念必須在應用層解決.-《阿里Java規范》

首先外鍵(Foreign Key)是什么東西

使用方案

假設有一個score表 id是自增id,score是分數,student_id是學號。

另一個student表,id是自增id,name是名字,student_id是學號。

那么設計這個的時候就希望有一個關聯關系,讓score的student_id指向student表的student_id,存在一個學生對應多個成績的關系。所以我可以使用以下SQL語句

ALTER TABLE score
ADD CONSTRAINT FOREIGN KEY (student_id)
REFERENCES student(student_id);

創建一個外鍵索引完成這個規則

完成后的表關系如下

外鍵原理

被指向的字段,具有唯一性

可以保證成績字段的一致性,即每一次插入一個score數據,首先要檢測是否student表存在這個id,保證一致性

如果在外鍵類型上使用CASCADE,則會保證在做更新和刪除sutudent表的student_id時,觸發一次級聯操作,會同步更新score表的student_id或者刪除student_id.

外鍵類型RESTRICT 也同樣會做一次檢測,但不會做級聯操作,而是直接拒絕操作。

場景思考

知道外鍵是什么后,我們來思考一個場景:

現在有一個電商系統,用戶有一個賬戶id,商品有一個商品id,這兩個字段和訂單綁定,此時訂單id和賬戶表ID構成一個外鍵關系,同時和商品表id也構成一個外鍵關系,那么我每次生成一筆訂單,就需要向另外兩張表查詢檢測一次數據,那么就存在幾個問題:

  • 增刪改觸發這個查詢操作的性能消耗,服務器系統是否允許
  • 在其他表查詢會上需要對其他表做一個內部鎖,是否存在高並發死鎖情況
  • 數據一致性全部交給數據庫服務器,數據庫服務器是否能夠承受

這些問題在互聯網公司會顯得格外嚴重,因為訪問流量大的時候以上問題基本上是完全無法得到MySQL系統本身解決的

同時在做分庫分表設計的時候,外鍵約束就會顯得格外離譜。

同時MySQL系統的外鍵設計是背離部分SQL標准的

引用自博客園Eden: (https://www.cnblogs.com/discuss/articles/1862244.html)

對SQL標准的背離:如果ON UPDATE CASCADE或ON UPDATE SET NULL遞歸更新相同的表,之前在級聯過程中該表一被更新過,它就象RESTRICT一樣動作。這意味着你不能使用自引用ON UPDATE CASCADE或者ON UPDATE SET NULL操作。這將阻止級聯更新導致的無限循環。另一方面,一個自引用的ON DELETE SET NULL是有可能的,就像一個自引用ON DELETE CASCADE一樣。級聯操作不可以被嵌套超過15層深。

對SQL標准的背離: 類似一般的MySQL,在一個插入,刪除或更新許多行的SQL語句內,InnoDB逐行檢查UNIQUE和FOREIGN KEY約束。按照SQL的標准,默認的行為應被延遲檢查,即約束僅在整個SQL語句被處理之后才被檢查。直到InnoDB實現延遲的約束檢查之前,一些事情是不可能的,比如刪除一個通過外鍵參考到自身的記錄。

處理

因為以上問題,我們通常在建模時隱性設計外鍵約束,實際實現采用業務邏輯模擬外鍵的方式處理,這樣可以解決把一致性全部放在DBA上的性能問題,同時我們可以采用允許臟數據存在,然后定時數據清理的方案去保證數據處理的分時性能,避免高峰處理。

這樣的好處:

  • 解決性能問題
  • 增加了可擴展性,框架遷移不用在數據庫系統內部實現邏輯約束
  • 分庫分表的時候方便
  • 不會在DB層面造成死鎖

反推:是否可以使用外鍵約束

我覺得在部分業務場景下是可以考慮使用的,回到最開始的例子,教務系統的成績模塊重要的點不再是性能問題,而是高可靠,因為對學校來說,系統存在以下特點:

  • 數據量較少,一個學校學生最多不超過10萬人,通常在5000-50000這個區間內,對DB來說這是一個很小的數據量
  • 數據不容許出錯,因為成績和學生的人身利益直接掛鈎
  • 能夠進行數據修改操作的用戶極少,只有教務處錄入成績的老師。
  • 如果放在業務部分,如果出現student表student_id在第一次被刪除后,未清理score表數據,這個student_id短時間內被再次使用,而沒有做數據清理,就容易出現成績復用錯誤,諸如此類

所以 不得使用外鍵與級聯,一切外鍵概念必須在應用層解決。 大部分情況下正確,但同樣我認為需要分業務場景解決,並不能一竿子打死。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM