Mysql

我如何證明刪除外鍵的行為不會破壞現有數據?

  • May 13, 2019

TL;DR:證明在實踐中,alter table table_name drop foreign key constraint_name語句的執行不會破壞現有數據。重要的考慮是語句本身的執行;考慮事實後的數據更改無關緊要。(以此類推:打開馬厩的門是有害的行為,而不是奔馬。)

我的老闆和我對是否在 MySQL/InnoDB 數據庫中使用外鍵有不同意見。我支持使用它們來執行 RI 並利用ON DELETE CASCADEand ON UPDATE RESTRICT/ SET NULL,而他反對(相信他可以在應用程序級別執行 RI)。

他的論點主要是:

  1. Drupal 不使用它們並且沒有它們也能很好地相處,那麼我們為什麼要這樣做呢?
  2. 當您需要更改數據和/或結構時,它們太不靈活了。
  3. 他已將它們從現有表中刪除以進行更改,這導致數據損壞僅在數週或數月後才會在高流量/高活動站點上引起注意,因此他寧願不使用它們。

我的論點主要是:

  1. 並非 Drupal 5-7 (MyISAM, SQLite 3) 支持的所有數據庫/數據庫引擎都預設強制執行FK,因此 Drupal 僅將它們保留為文件,而在 D8 中可能會有所不同。
  2. 是的,處理它們可能會很痛苦,但問題可能在於開發人員的規劃/設計不佳,而不是 FK。
  3. 當然,在 DBMS 級別不使用 FK 執行 RI 比其他方式更有可能導致數據損壞。(例如,當現有內容引用必須具有特定狀態的使用者時,D6 的使用者引用模組不限制更改使用者狀態)。
  4. 讓程式碼做/嘗試 DBMS 已經做的事情是浪費時間和資源。他怎麼能保證他的程式碼和 DBMS 一樣好(或更好)?

本質上,如果我能證明刪除外鍵本身的行為(不管後續數據插入/更新)不會破壞現有數據,他就會接受我的想法。drop foreign key我無法清楚地證明它們的有用性/優勢,因為除了比較執行前的數據與執行後的數據之外,我不確定如何令人滿意地觀察/記錄執行後立即產生的效果。

那麼,我如何說服我的老闆我們應該使用外鍵,證明以後刪除/更改它們的行為不會破壞現有數據,而使用它們不會引起任何問題?我將如何最好地設置實際使用測試?

注意:我並不是很想證明我是正確的(從自負的角度來看)使用 FK,但是在 DBMS 級別使用它們比在應用程式碼中更有益於數據和應用程式碼等級。

直接反駁觀點:

Drupal 不使用它們並且沒有它們也能很好地相處,那麼我們為什麼要這樣做呢?

Drupal 支持許多數據庫層,也許其中至少有一個不支持 FK,他們選擇堅持使用​​最低的通用特性集?很多人確實使用它們,人們不使用它們的一個數據點相對沒有意義。我知道有人在車上不繫安全帶,但我和其他大多數人一樣…

當您需要更改數據和/或結構時,它們太不靈活了。

如果您將結構更改到需要更改 FK 關係的程度,那麼現有設計中的任何內容都可能看起來不靈活(特別是如果現有設計與您開始建模的系統不匹配,這可能就是您為什麼正在尋求改變現有結構)。

在更改數據時,它們故意不靈活。它們旨在不允許您以可能損害完整性的方式更改數據,即使是暫時的。詢問外鍵約束會停止數據修改的範例,並且對於每個範例,我們將能夠解釋為什麼這是一件好事以及如何使用約束來實現您的目標而不破壞它(或者相反,我們可能會而是告訴您為什麼特定的 FK 關係是錯誤的 - 但這不會使其他 FK 錯誤,它只是意味著您的模型的那部分存在問題)。

他已將它們從現有表中刪除以進行更改,這導致數據損壞僅在數週或數月後才會在高流量/高活動站點上引起注意,因此他寧願不使用它們。

刪除它們不會導致腐敗。刪除它們允許其他一些程式碼中的錯誤隨著時間的推移導致損壞,並且沒有被注意到。如果密鑰已經到位,則該過程會引發錯誤,並且可能因此會注意到並修復它的問題,而不是靜默允許破壞更多數據直到注意到。刪除約束所做的所有事情都是停止數據庫對未來的插入/更新/刪除執行約束——它不會影響現有數據。

我不確定您將如何最終向一個確定情況並非如此的人證明。

我能想到的唯一證據是第一原則:重申外鍵約束實際上做了什麼,從而表明它們不會允許出現不一致,如果有這個人想到的腐敗的具體例子,你可以嘗試創造密鑰到位的問題(表明密鑰會導致錯誤而不是允許創建不一致)。

更具體地說,關於刪除約束的直接影響:表明刪除它們根本不會改變現有數據。創建數據庫的副本,刪除副本中的鍵,並執行數據的完整比較以顯示由於解除約束而沒有發生任何變化。

他反對(相信他可以在應用程序級別執行 RI)。

充其量這是對開發/測試時間的錯誤利用,最壞的情況是它會為以後製造一場噩夢。您正在重新發明輪子,可能效率低下並且可能存在錯誤,您必須在程式碼現在和未來每個應用程序中觸及該數據的任何地方實現您的新輪子,而不是每次都簡單地讓數據庫處理它,如果其中一個位程式碼有一個錯誤,數據可能永遠失去所有應用程序的完整性。

當然,DBMS 無​​法為您強制執行複雜的業務規則,因此您必須在您的 BL 層中實現它們,但是對於這樣的基礎知識,讓 DB 來處理它。

一個沒有提到但我聽過好幾次的額外的:當我們對父對象進行更改時,它們效率低下

這是因為大多數 DBMS 不會為每個 FK 自動創建索引,許多人認為他們會這樣做,並且對他們沒有看到他們期望的性能指標感到驚訝。數據庫不這樣做,因為在不需要時可能會非常浪費(這比您預期的更常見)。如果您需要在 FK 的列上建立索引,以使級聯更新/刪除(或僅在該方向上的簡單連接查詢)高效,請創建一個。

引用自:https://dba.stackexchange.com/questions/74457