憑什么不讓使用外鍵???你知道嗎?
MySQL 外鍵(Foreign Key)是用于建立表之間關(guān)系的,它定義了一個表中的一列或一組列,這些列的值必須在另一個表的主鍵列中存在。
MySQL 外鍵最大的作用就是有助于維護數(shù)據(jù)的一致性和完整性。
- 一致性:如果一個訂單表引用了一個客戶表的外鍵,外鍵可以確保訂單的客戶 ID 存在于客戶表中,從而保持數(shù)據(jù)的一致性。
 - 完整性:外鍵可以防止在引用表中刪除正在被其他表引用的記錄,從而維護數(shù)據(jù)的完整性。
 
但是,其實在很多大型互聯(lián)網(wǎng)公司中,很少用外鍵的,甚至阿里巴巴Java開發(fā)手冊中明確規(guī)定了:
【強制】不得使用外鍵與級聯(lián),一切外鍵概念必須在應(yīng)用層解決。
說明: 以學(xué)生和成績的關(guān)系為例,學(xué)生表中的 student_id 是主鍵,那么成績表中的 student_id 則為外鍵。如果更新學(xué)生表中的 student_id,同時觸發(fā)成績表中的 student_id 更新,即為級聯(lián)更新。外鍵與級聯(lián)更新適用于單機低并發(fā),不適合分布式、高并發(fā)集群;級聯(lián)更新是強阻塞,存在數(shù)據(jù)庫更新風(fēng)暴的風(fēng)險;外鍵影響數(shù)據(jù)庫的插入速度。
那么,使用外鍵會帶來哪些問題呢?(另外我出了一份Java面試寶典,里面有800多道面試常考題目)
先舉個例子,我們有兩張表:Orders(訂單)和 OrderItems(訂單項)。這兩個表之間通過外鍵建立關(guān)系,訂單項表中的外鍵引用訂單表的訂單號。
CREATE TABLE Orders (
    OrderID INT PRIMARY KEY,
    CustomerID INT,
    OrderDate DATE,
    -- 其他訂單信息
);
CREATE TABLE OrderItems (
    ItemID INT PRIMARY KEY,
    OrderID INT,
    ProductID INT,
    Quantity INT,
    -- 其他訂單項信息
    FOREIGN KEY (OrderID) REFERENCES Orders(OrderID)
);性能問題
首先就是性能問題,因為外鍵會增加數(shù)據(jù)庫的維護負擔(dān),因為每次插入、更新或刪除數(shù)據(jù)時,數(shù)據(jù)庫都需要檢查外鍵約束的完整性。
這兩張表中共有兩個索引,一個是Orders表的主鍵索引,一個是OrdersItems表的外鍵索引,這就使得每次插入、更新或刪除訂單或訂單項時,數(shù)據(jù)庫需都要維護這兩個索引,這可能會導(dǎo)致性能開銷。
其次,在插入新的訂單項之前,數(shù)據(jù)庫需要執(zhí)行數(shù)據(jù)一致性檢查以確保引用的訂單號在 Orders 表中存在。這額外的檢查可能增加插入訂單項的執(zhí)行時間。
鎖競爭問題
還有就是比較容易忽略的鎖競爭問題。當(dāng)多個事務(wù)同時嘗試插入或更新訂單項時,它們就需要去檢查訂單表,就需要獲得額外的鎖,以確保一致性。這可能導(dǎo)致事務(wù)之間的鎖競爭,降低并發(fā)性能。(另外我出了一份Java面試寶典,里面有800多道面試常考題目)
一旦有了鎖競爭,就可能帶來更加嚴重的死鎖問題,所以都是需要盡量避免的。
Merge無法適應(yīng)分庫分表
當(dāng)數(shù)據(jù)量打的時候,我們就要考慮分庫分表了,但是在分庫分表環(huán)境中,相關(guān)數(shù)據(jù)可能分布在不同的數(shù)據(jù)庫中,外鍵通常難以跨越不同數(shù)據(jù)庫來建立關(guān)系。更重要的是,分庫分表環(huán)境中,數(shù)據(jù)的一致性可能更難維護??鐜焓聞?wù)搞不定。
以上,就是一些比較重要的原因吧。其實最主要的還是外鍵約束會帶來一些額外的開銷及鎖競爭。而在很多大型互聯(lián)網(wǎng)公司中,都是會盡量避免的。
就像大廠會使用RC來替代RR一樣,會盡可能的降低鎖的發(fā)生,一方面提升性能,一方面避免死鎖。















 
 
 

















 
 
 
 