Mysql

關係數據庫中的完整性約束——我們應該忽略它們嗎?

  • November 20, 2020

我正在與我工作的公司的開發人員進行長期討論,因為他們說最好擺脫關係數據庫中的關係強制(通過 FOREIGN KEY 約束定義),以加快大型查詢並獲得更好的結果表現。

正在考慮的平台是 MySQL 5.x,沒有設置 FOREIGN KEY,甚至相關表的一些 PRIMARY KEY 約束都失去了,至少對我來說是不合理的。也許他們是對的,我是錯的,但我沒有足夠的論據來討論這種情況。

三年來,這一直是首選方法。我是這家公司的新人(只有一個月),但由於產品“有效”,因此對增強數據庫猶豫不決;儘管如此,我注意到的第一件事是載入一個頁面需要 1 分鐘(是的,60 秒!)。

目前狀態背後的主張之一是“非規範化”數據庫比規範化數據庫更快,但我不認為這是真的。

大多數相關查詢都包含 JOIN 操作,這使得它們在處理大量數據(數據庫包含數百萬行)時執行非常、非常、非常慢。

通常,“CRUD”操作的處理是在應用程式碼級別實現的;例如,為了刪除一些數據 FROM,比方說TableA

  • 有必要首先動態檢查和行之間是否存在某種關係,TableA``TableB
  • 如果“檢測到”所述關係,則應用程式碼將不允許刪除相關行,但是
  • 如果由於某種原因應用程式碼失敗,則刪除操作將“成功”,無論涉及的行和表是否有任何關係。

您能幫我詳細闡述一個好的、準確和可靠的答案來豐富辯論嗎?


注意:也許以前有人問過(並回答過)這樣的問題,但我通過Google找不到任何東西。

如果,如您的文章中所述,其目的是創建一個關係數據庫(為簡潔起見,RDB),因此,預計它的功能是這樣的,簡短的回答是:

  • ,您不應忽視數據完整性約束

主要目標應該是按原樣管理相關數據:一項非常有價值的組織資產,實現上述目標的可靠方式是採用基於合理理論的技術手段。

因此,作為一名數據庫專業人士,您可以利用EF Codd 博士提供的最先進和優雅的關係模型機制來執行業務規則,並避免最終會出現的(技術和組織)問題,如果它們沒有被利用。

在這方面,我將分享(a)我對約束的總體看法,以及(b)關於數據庫事務狀態和有爭議的工作環境的幾個考慮如下。

FOREIGN KEY 約束、數據關係和參照完整性

RDB 必須高度準確地反映感興趣的業務上下文的特徵,這肯定需要由遵循最佳實踐的建模師或設計師領導的深入概念級分析,並在業務專家不可或缺的幫助下進行。該分析必須產生正確的辨識並製定適用的業務規則

因此,如果這樣的建模者已經確定相關數據之間存在相互關係,他或她必須配置相應的邏輯級限制,以便數據庫管理系統(DBMS)可以保證數據與確切的特徵保持一致,並且上述 分析 中 確定 的規則.

關於正在討論的數據庫,可以推斷已經確定了相關的相互關係,因為您提到有一種程序(並且易於規避)嘗試通過應用程式碼(其中是一種前關係方法)在任何情況下都必須“觸摸”數據庫以嘗試驗證所述相互關係的完整性。

但是,如您所知,這不是保護參照完整性的最佳技術,因為關係科學為此目的規定了一種非常強大的工具,即外鍵 (FK) 約束。這些約束很容易創建(通過優越的聲明性方法),因為它們是單個句子,可以避免訴諸不必要且容易出錯的臨時程序。值得注意的是,FK 約束的執行速度已經被專業的程序員高度優化(並且主要平台供應商已經為此工作了幾十年)。

此外,由於 RDB 必須是一個獨立的(自我保護、自我描述等)軟體組件,能夠被多個應用程序(桌面、自動、Web、移動、它們的組合)訪問,因此它不應該是與任何這些應用程序的程式碼“耦合”。

同樣,作為重要的組織資源的數據自然往往比應用程序、應用程序程序員、應用程序開發平台和程式範式更長壽。

PRIMARY KEY 約束和重複行的含義

當——從概念上講——一種特定的事物在商業環境中被認為是重要的,數據庫建模者必須(1)確定它的相關特徵——即它的屬性——,確認這種事物作為實體實例原型——即,實體類型 - 並且 (2) 通過由邏輯設計中的一個或多個列集成的**表來表示它。

然後,就像在現實世界的業務中區分給定實體類型的每個單獨實例**至關重要一樣,**表中包含的每個對應也必須唯一區分。如果一個表沒有聲明任何 KEY,它最終會保留重複,如果有兩行或多行保留完全相同的值,那麼它們都具有相同的含義,它們都代表相同的事實

在這一點上,由於多種原因,應該丟棄重複的行。從理論的角度來看,設計者必須確保每一行始終是唯一的,以使表在 SQL 數據子語言允許的範圍內工作(對數據操作操作有重要影響)。此外,從資訊的角度來看,如果多行代表同一個事實,記錄它們不僅是多餘的,而且是有害的,如下所示:

  • 假設有人在某個表中插入了兩個相同的行。
  • 後來,其他人來了,只更新了一次重複。因此,其他事件不再是最新的。
  • 隨後,另一個人更新了迄今為止尚未修改的事件。以這種方式,兩個副本在不同的時間點都經歷了不同的變化。
  • 之後,當有人有興趣選擇相關行所傳達的資訊時,他或她可以找到它的兩個不同“版本”。

這樣:

  • 哪個“版本”可以被認為是正確、可靠的?
  • 哪一個準確地反映了現實世界?

如您所知,這種現象甚至會產生法律影響,而這種情況肯定是非常重要的。

此外,處理此類矛盾(可能通過某種“更新同步”)所必須花費的時間和精力應該更好地投入到真正為您的組織創造價值的任務上。因此,應該通過設計來避免保留矛盾的行,以保持數據庫的一致性。

這就是為什麼主鍵 (PK) 的標識相應約束的聲明應始終由數據庫設計者執行。但也必須提到的是,一個表可能有多個列或列組合,這些列包含唯一標識每一行的值;因此,除了設置 PK 約束(由於實用原因理想地設置為 PRIMARY)外,設計人員還必須在應用時聲明一個或多個 ALTERNATE KEY(通常通過一個或多個 UNIQUE 加上 NOT NULL 約束定義)(即很常見)。

PK 的另一個優點是,當“遷移”到其他表以參與單個或複合 FK 時,它們可以幫助強制執行數據之間存在的關係/關聯的*基數比。*所有這一切,是的,通過簡單而有效的聲明性設置,由 DBMS 始終確保。

(目前)CHECK 約束和單行驗證

讓我們不要忘記(目前)CHECK 約束的相關性,它以聲明方式限制行的有效列值集(這可能看起來很簡單,但實際上是關係 DBMS 的基本特徵),也有助於確保業務上下文的規則始終精確地反映。

當您用 MySQL 標記標記您的問題時,從版本8.0.16(另請參閱此 MySQL 伺服器團隊部落格文章)開始,終於有了這樣一個平台!強制執行這種類型的約束。在這方面,必須提到的是,在所有以前的版本中,這個 DBMS 確實允許聲明 CHECK 限制,但忽略了它的強制執行!,可以理解的是,自 2004 年以來,這種情況被報告為錯誤

因此,如果使用舊版本,您將不得不通過其他方式處理此因素,例如ACID TRANSACTIONS、 TRIGGERS 或 DBMS 本身中的其他方法(有關此主題的資訊,請參閱@ypercubeᵀᴹ答案),以便數據繼續保持一致。

ASSERTION 約束:以聲明方式設置進一步的多行和多表業務規則

無論出於何種原因,包括 MySQL 在內的不同 SQL DBMS 都很難支持(如果有的話)的一個方面是以聲明的方式啟用多行和多表約束(顯然,超越了 PK 和 FK)。

就其本身而言,SQL 標準已經包含了多年以來的斷言。我不知道您的業務環境的哪些規則會從這種邏輯級驗證方法中受益,但作為數據庫設計人員,我認為在需要時使用一個或多個 ASSERTION 來約束數據會非常方便,儘管我不得不提一下從 DBMS 開發人員的角度來看,這種最重要的工具很難在物理抽象級別上實現。

自 2016 年以來,Oracle 供應商和/或開發人員似乎正在評估ASSERTION 支持,這將使 DBMS 更加符合關係,因此更加健壯和具有競爭力。我猜想,如果 (i) 他們的消費者繼續推動並且 (ii) Oracle 成功實施,那麼 (iii) 其他 DBMS 供應商/社區也將不得不啟用它們,並且它們的使用將開始傳播。當然,這將是數據管理領域的巨大進步,並且作為 Codd 博士設想的最獨特的工具之一,我個人希望我們能很快看到這種情況發生。

數據一致性和決策過程

如上所述,RDB 最重要的方面之一是它自己保證它保留的數據的一致性,並且只有當 RDB 符合建模者聲明的完整性約束時才能滿足所述一致性。

在這方面,必須具有完整性受到保護的表(在 DDL 結構中建立的那些),以便能夠創建可信賴的**派生表(例如,從多個表中檢索列的 SELECT 語句或視圖),因為必鬚根據基表生成派生表。

很明顯,人們在組織(和普通)決策過程中使用資訊作為主要工具。然後,如果數據庫提供的資訊不連貫且不准確,那麼基於這些資訊的決策將是不合理的(至少可以說)。這就是為什麼必須仔細設計和實施 RDB:它應該被建構為可以幫助其使用者做出有根據的決策的可靠資源。

“非規範化”

唉,“非規範化的數據庫比規範化的數據庫更快”是一個廣泛傳播的誤解,儘管它也是一個可以在邏輯、物理和實用的基礎上反駁的“論據”。

首先,非規範化必然意味著基表先前已經被規範化(憑藉在數據庫的邏輯抽象級別上實現的正式的、基於科學的過程)。

因此,假設該表實際上已正確規範化,則將其“非規範化”(與該詞的正式含義相反,這涉及向其附加屬於廣告中其他表並且也是其一部分的列hoc方式)可能有助於,例如,加速(在物理級別)僅處理一個或幾個特定的 SELECT 語句,而同時這樣的操作過程可能會破壞許多其他相關數據的執行操作操作(例如,幾個 INSERT、UPDATE、DELETE 和 SELECT 語句,或其組合包含在單個或多個 ACID TRANSACTIONS 中)。

此外,非規範化(無論是正式的還是非正式的)會引入更新/修改異常,從而降低數據庫的一致性,這個問題“可能”由複雜、昂貴且容易出錯的過程來處理,而所有這些都可以避免一開始。

支持規範化和“非規範化”表的物理級腳手架

旨在在現實世界中使用的邏輯(抽象)佈局(SQL-DDL 設計)顯然包含必須考慮的物理(具體)影響。

以這種方式,“非規範化”表必然會“更寬”(包含額外的列),這意味著它的行必然會更重(需要更多更大的物理級組件),這意味著底層計算過程(例如,那些與硬碟驅動器或記憶體有關的)很容易變慢。

相比之下,當然“更窄”(列更少)的規範化表將是“表現更快”的“更輕”元素(由更少和更小的物理組件提供服務),這將加速與,例如,數據寫入和讀取。

既然如此,很方便(a)正式和謹慎地規範化相關表,保持它們原樣,然後(b)利用任何可以優化數據檢索和修改速度的物理級資源,例如,實現謹慎高效的索引策略,啟用適當的軟體和硬體伺服器配置,升級網路頻寬能力等。

正在考慮並與您的同事聯繫的數據庫的功能

您問題的以下段落與數據檢索操作的速度有關:

$$ A $$s 產品“有效”,對增強數據庫猶豫不決;儘管如此,我注意到的第一件事是載入一個頁面需要 1 分鐘(是的,60 秒!)。

如果載入某個頁面需要那麼長時間,那麼系統的使用者顯然沒有得到適當的服務;因此,即使它“有效”,它的功能似乎也根本不是最佳的,這表明您使整個電腦化資訊系統(數據庫和應用程序)更高效的意圖得到了很好的維持,並表現出非常建設性的態度.

然後,即使科學肯定支持你,因此你應該保持堅定的姿態,我建議以外交方式處理這種情況,因為歸根結底,你的雇主、同事和你自己都在共同努力,以使整個組織更成功。因此,這是您應該強調的一個論點,即儘管他們在其他方面做得非常好,但改進一般和特定的數據管理實踐可以大大有助於產生更多的組織和個人成長。

大多數相關查詢都包含 JOIN 操作,這使得它們在處理大量數據(數據庫包含數百萬行)時執行非常、非常、非常慢。

值得注意的是,JOIN 運算符是與數據的關係操作相關的重要強大的元素。然後,儘管更強大的平台以相對更快的執行速度為其提供服務,但您描述的情況很可能是設計效率低下的症狀(在抽象的概念、邏輯和物理級別)。所以,我的第一眼估計是:

  • INDEX 設置可能需要改進。
  • 需要審查 PK 和 FK 列類型和大小定義(我完全同意@Rick James關於他的 PK考慮,因為在適當的情況下,複合 KEY 往往比附加代理更有效)。
  • 進一步的(正式的、基於科學的)規範化可能有助於緩解這些問題,因為在正確的情況下(即在精心設計的 RDB 中執行),JOIN 的執行速度非常快

此外,是的,正如@TommCatt他的回答中提到的那樣,有時查詢的(邏輯)重寫會修改其(物理)執行計劃,從而加速數據讀取/寫入,這是一個應該明確考慮的因素。

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