參考:https://draveness.me/whys-the-design-database-foreign-key/ 為什么數據庫不應該使用外鍵
在關系型數據庫中,外鍵也被稱為關系鍵,它是關系型數據庫中提供關系表之間連接的多個列,這一組數據列是當前關系表中的外鍵,也必須是另一個關系表中的候選鍵(Candidate Key),我們可以通過候選鍵在當前表中找到唯一的元素。、
在通常情況下,我們都會使用關系表中的主鍵作為其他表中的外鍵,這樣才可以滿足關系型數據庫對外鍵的約束。
ALTER TABLE posts ADD CONSTRAINT FOREIGN KEY (author_id) REFERENCES authors(id);
外鍵的類型,最常見的也就是 RESTRICT
和 CASCADE
兩種,其中 RESTRICT
為外鍵的默認類型,不同類型的外鍵會帶來不同的額外開銷,而這些額外開銷就是我們不使用外鍵的理由:
- 使用
RESTRICT
會在更新或者刪除記錄時對外鍵對應的記錄是否存在進行一致性檢查; - 使用
CASCADE
會在更新或者刪除記錄時觸發級聯更新或者刪除操作;
一致性檢查
在執行如下所示的操作時都會觸發數據庫對外鍵的檢查: 通過額外開銷,保證數據庫數據完整性
- 向
posts
表中插入數據時,檢查author_id
是否在authors
表中存在; - 修改
posts
表中的數據時,檢查author_id
是否在authors
表中存在; - 刪除
authors
表中的數據時,檢查posts
中是否存在引用當前記錄的外鍵;
模擬外鍵一致性檢查效果:
- 向表中插入數據或者修改表中的數據時,都應該執行額外的
SELECT
語句確保它引用的數據在數據庫中存在; - 在刪除數據之前需要執行額外的
SELECT
語句檢查是否存在當前記錄的引用;
級聯操作
配置級聯類型外鍵
ALTER TABLE posts ADD CONSTRAINT FOREIGN KEY (author_id) REFERENCES authors(id) ON UPDATE CASCADE ON DELETE CASCADE;
- 當客戶端更新
authors
表中記錄的主鍵時,數據庫會同時更新posts
表中所有引用該記錄的外鍵; - 當客戶端刪除
authors
表中的記錄時,數據庫會刪除所有與authors
表關聯的記錄;
復雜的級聯操作:
當客戶端想要在數據庫中刪除 authos
表中的數據時,如果我們同時在 authors
和 posts
中指定了級聯刪除的行為,那么數據庫會同時刪除所有關聯的 posts
記錄以及與 posts
表關聯的 comments
數據。
數據量大時可能造成系統問題;建議手工SQL完成業務關聯表的刪除
不使用外鍵的理由
MySQL、PostgreSQL 等關系型數據庫很難水平擴容,但是無狀態的服務往往都可以很容易地擴容。
由於外鍵等特性需要數據庫執行額外的工作,而這些操作會占用數據庫的計算資源,所以我們可以將大部分的需求都遷移到無狀態的服務中完成以降低數據庫的工作負載。