前言
數據庫規範化的產生主要是由模式設計(Schema Design)而推動的。模式設計的目標是爲特定的數據庫應用程序選擇最合適的模式。模式的選擇由用戶提供和依賴項捕獲的應用程序數據的語義信息指導。
常見的方法是從一個普遍的關係開始,並應用分解來創建滿足某些形式的新關係,使用範式進行規範化就是其中之一。
範式的種類(Normalisation Form)
根據約束強弱的差別,範式的種類從弱到強依次是:
(弱約束)1NF → 2NF → 3NF → BCNF → ... (強約束)
其中:
- 第一範式(1NF):不基於任何的約束,要求每個字段的值都是單一值,用於排除重複元組的出現。
- 第二範式(2NF):滿足第一範式,數據對錶的主鍵與候選鍵有依賴關係。
- 第三範式(3NF):滿足第二範式,所有非主鍵屬性都只和候選鍵有相關性,非主鍵屬性之間獨立無關。
- Boyce–Codd 範式(BCNF):滿足第三範式,對於任意函數依賴 X → A,都滿足 X 是 R 的一個超鍵。
- 第四範式(4NF):每個非平凡的多值依賴都有一個超鍵。
- 第五範式(5NF):候選鍵隱含了每個非平凡的連接依賴關係。
- 第六範式(6NF):每個連接依賴都是平凡的。
下面暫且詳細介紹一下 BC 範式和第三範式。
BC範式 (BCNF)
定義
一個數據庫 R 滿足,對於任意一個非平凡的函數依賴 X → A,X 都是一個超鍵(superkey)。
根據定義可知,當一個數據模式是 BCNF 時,基於函數依賴的所有數據冗餘都會被清除。但是使用 BCNF 設計的數據模式不一定是一個好的設計。該範式的核心在於,不重複在數據庫中描述同樣的事實(值、函數依賴等)。
BC範式分解算法
- 輸入:關係模式 R',以及 R' 的所有函數依賴的集合 ∑。
- 輸出:滿足 BC 範式的所有關係模式的集合 S,且每個關係模式都包含一組函數依賴的集合。
- 步驟:
- 從 S = { R' } 開始;
- 迭代對 S 中的每一個關係模式 R 進行一下操作,直至 S 不再變化:
- 找出 R 中違反 BC 範式的任意一個非平凡函數依賴 X → Y;
- 在集合 S 中分別用兩個關係模式 XY 和 (R - Y)來替代 R。
- 把 ∑ 中的每個函數依賴映射到最終的關係模式集合 S 中。
當我們對關係模式進行分解時,需要考慮以下兩個特點:
- 無損耗連接(Lossless join):,將自然連接操作應用於分解後的關係時不允許生成假元組的可能性。
- 依賴保留(Dependency preservation):確保每個功能依賴項都可以從分解後的功能依賴項中推斷出來。
根據上面的算法,最後得到的 S 中的每一個關係模式 R,都存在對應的函數依賴,且都滿足 BC 範式。但最開始 ∑ 中的函數依賴並不一定會完全保留下來,有部分的函數依賴可能在分解過程中丟失了,但是這些依賴可以通過內連接不同的關係模式得到恢復。因此,BCNF 可以生成一個無損耗的分解,但不一定能生成一個既無損耗又能保留依賴的分解。
第三範式(3NF)
第三範式是一種比 BC 範式寬鬆一點的約束範式。與 BC 範式相比,第三範式總是可以保證無損耗連接和依賴保留,也就是說,滿足第三範式的分解結果不會丟失原來的所有函數依賴。
定義
一個數據庫 R 滿足,對於任意一個非平凡的函數依賴 X → A,X 都是一個超鍵(superkey)或者 A 是主要屬性(prime attributes)。
由定義可知,滿足第三範式的關係模式,可能會保留一些數據冗餘,但排除了一些多餘的函數依賴,比如:
- 部分函數依賴(Partial FD):X 是某個鍵的真子集,一個非主要屬性 A 依賴於 X,則稱 X → A 是部分函數依賴。
- 傳遞函數依賴(Transitive FD):一個非主要屬性 A 依賴於 X,但 X 不是任何鍵的真子集,則稱 X → A 是傳遞函數依賴。
例如,一個關係模式 R = { A,B,C,D},∑ = { A → B,B → C },其中它僅有一個鍵爲 { A,D }。那麼
- A → B 是一個部分函數依賴(A 是鍵的真子集,B 不是主要屬性)。
- B → C 是一個傳遞函數依賴(B 不是鍵的真子集,C 不是主要屬性)。
第三範式分解算法
- 輸入:關係模式 R,以及 R 的所有函數依賴的集合 ∑。
- 輸出:滿足 3NF 的所有關係模式的集合 S,且每個關係模式都包含一組函數依賴的集合。
- 步驟:
- 從 S = { ∅ } 開始,並找出集合 ∑ 的最小覆蓋 ∑‘;
- 分別將最小覆蓋 ∑‘ 中的每一個函數依賴的左邊和右邊屬性分爲一組
- (重複)對於每個最小覆蓋 ∑‘ 中獨特的左邊屬性 X_i,其滿足 X_i → A_1, X_i → A_2,。。。, X_i → A_k;
- 添加關係模式 R_i = X_i ∪ { A_1 } ∪ { A_2 } 。。。 ∪ { A_k } 到集合 S 中。
- 清除集合 S 中的冗餘關係模式,比如去掉 R_i 如果 R_i ⊆ R_k。
- 如果集合 S 中不包含一組 R_i 能作爲 R 的超鍵,就要添加一組鍵,記爲 R_0。
- 把最小覆蓋 ∑’ 中的每一個函數依賴映射到 S 中的每個關係模式 R 上。
第三範式分解僅僅可以減少數據冗餘,但不能完全消除,還是會存在一部分的冗餘,因此滿足 3NF 的數據模式仍然有可能會出現數據更新異常的現象。要想避免更新異常的情況,就要使用 BC 範式或者約束更強的範式來消除所有的冗餘。