1NF
、2NF
、3NF
、BCNF
、4NF
、5NF
都是數據庫設計中的范式(Normalization),用于確保數據庫中的數據結構盡可能地減少冗余,避免更新異常、插入異常、刪除異常等問題,從而提高數據的存儲效率和一致性。
本篇文章簡單講解下各個范式的含義,以及如何快速記住它們。
1. 第一范式(1NF)
定義:一個關系(表)滿足第一范式,意味著表中的每個字段(列)都必須是原子的(atomic)。即每個字段只能包含一個單一的值,而不能是集合、數組或多值。
通俗來說:數據表的每個單元格只能存儲一個值,不能有重復的組或多值字段。
問題:如果數據表不滿足1NF,可能存在列包含多個值的情況,比如一個列存儲多個電話號碼。
例子: 假設有一個“學生課程”表,記錄學生選修的課程。初始狀態可能是這樣的:
學生ID | 學生姓名 | 選修課程 |
---|---|---|
1 | 張三 | 數學, 英語 |
2 | 李四 | 物理, 化學 |
這個表不符合1NF,因為“選修課程”列包含多個值。為滿足1NF,我們需要將每個學生的每一門課程分開:
學生ID | 學生姓名 | 選修課程 |
---|---|---|
1 | 張三 | 數學 |
1 | 張三 | 英語 |
2 | 李四 | 物理 |
2 | 李四 | 化學 |
這樣,每個字段都是原子的。
2. 第二范式(2NF)
定義:一個關系(表)滿足第二范式,首先它必須滿足第一范式,并且所有非主屬性(即不是主鍵的屬性)完全依賴于主鍵,而不是部分依賴。也就是說,如果主鍵是由多個列組成的,那么非主屬性必須依賴于整個主鍵,而不能只依賴于主鍵的某一部分。
通俗來說:如果主鍵是復合主鍵(由多個字段組成),那么每個非主鍵字段必須依賴于整個主鍵,而不能只依賴其中的一部分。
問題:如果存在部分依賴,就可能會導致冗余數據。例如,一個復合主鍵的表中,如果有字段只依賴于主鍵的一部分,那么這些字段的重復值就會導致數據冗余。
例子: 繼續考慮“學生課程”表,如果我們加入“教師姓名”字段,這樣的表結構如下:
學生ID | 課程ID | 學生姓名 | 選修課程 | 教師姓名 |
---|---|---|---|---|
1 | 101 | 張三 | 數學 | 王老師 |
1 | 102 | 張三 | 英語 | 李老師 |
2 | 101 | 李四 | 物理 | 王老師 |
2 | 103 | 李四 | 化學 | 張老師 |
主鍵是“學生ID”和“課程ID”的組合。在這個例子中,學生姓名和教師姓名都依賴于學生ID和課程ID,但學生姓名只依賴于學生ID,而教師姓名只依賴于課程ID。因此,我們存在部分依賴,表不滿足2NF。
為滿足2NF,我們應該將“學生姓名”單獨提取到一個“學生”表中,將“教師姓名”提取到一個“課程”表中:
學生表:
學生ID | 學生姓名 |
---|---|
1 | 張三 |
2 | 李四 |
課程表:
課程ID | 選修課程 | 教師姓名 |
---|---|---|
101 | 數學 | 王老師 |
102 | 英語 | 李老師 |
103 | 化學 | 張老師 |
學生選課表:
學生ID | 課程ID |
---|---|
1 | 101 |
1 | 102 |
2 | 101 |
2 | 103 |
這樣就解決了部分依賴問題,表滿足了2NF。
3. 第三范式(3NF)
定義:一個關系(表)滿足第三范式,首先它必須滿足第二范式,并且每個非主屬性都不傳遞依賴于主鍵。也就是說,非主鍵字段不能依賴于其他非主鍵字段。
通俗來說:如果一個字段依賴于其他非主鍵字段,那么我們就有傳遞依賴。3NF要求消除這種依賴。
問題:傳遞依賴可能會導致冗余數據和數據一致性問題。
例子: 假設我們在“課程表”中添加了“課程時長”字段,并且規定“教師姓名”依賴于“教師工號”,即:
課程ID | 選修課程 | 教師工號 | 教師姓名 | 課程時長 |
---|---|---|---|---|
101 | 數學 | 1 | 王老師 | 40小時 |
102 | 英語 | 2 | 李老師 | 35小時 |
103 | 化學 | 3 | 張老師 | 50小時 |
在這個表中,“教師姓名”依賴于“教師工號”,而“教師工號”又依賴于主鍵(課程ID)。因此,“教師姓名”通過“教師工號”傳遞依賴于課程ID。為了消除這種傳遞依賴,我們需要將“教師工號”和“教師姓名”提取到單獨的“教師”表中:
教師表:
教師工號 | 教師姓名 |
---|---|
1 | 王老師 |
2 | 李老師 |
3 | 張老師 |
這樣就消除了傳遞依賴,表滿足了3NF。
4. 巴斯-科德范式(BCNF)
定義:
一個表滿足 BCNF(Boyce-Codd Normal Form)要求滿足以下條件:
- 必須滿足 3NF。
- 對于每一個函數依賴(A → B),A 必須是候選鍵(candidate key)。也就是說,任何決定其他屬性的字段都必須是候選鍵。
通俗來說:
- 在 3NF 中,我們要求沒有傳遞依賴,而 BCNF 要求每個決定其他字段的字段,必須是候選鍵。
- 候選鍵 是指在沒有其他列可以作為鍵的情況下,可以唯一標識表中一行的列。
為什么需要 BCNF?
3NF 有時不能處理一些更復雜的依賴關系,特別是當表中的某些非主屬性決定了其他非主屬性時,雖然這些屬性滿足了3NF,但卻不能保證表的完美規范化。
BCNF 示例:
假設我們有以下表格,記錄了課程、學生、教師和教室的信息:
課程ID | 學生ID | 教師工號 | 教師姓名 | 教室 |
---|---|---|---|---|
101 | 1 | 1 | 王老師 | A101 |
101 | 2 | 1 | 王老師 | A101 |
102 | 1 | 2 | 李老師 | B201 |
102 | 3 | 2 | 李老師 | B201 |
-
假設 課程ID → 教室(即每門課程對應一個教室),教師工號 → 教師姓名(即每個教師工號對應一個教師姓名),課程ID → 教師工號(即每門課程由一個特定的教師授課)。
依賴關系:- 課程ID → 教室
- 課程ID → 教師工號
- 教師工號 → 教師姓名
從上面的表格來看,我們發現 課程ID 確定了 教室 和 教師工號,但 教師工號 又決定了 教師姓名。這意味著 教師姓名 是由 教師工號 確定的,而 教師工號 不是候選鍵。教師工號 → 教師姓名 的依賴關系違反了 BCNF,因為 教師工號 不是候選鍵。
解決方案:
為了使表符合 BCNF,我們需要將表拆分為兩個表:
1. 課程表:包含課程和教室的信息。
2. 教師表:包含教師工號和教師姓名的信息。
3. 選課表:包含學生ID、課程ID和教師工號的信息。拆分后的表:
-
課程表:
課程ID 教室 101 A101 102 B201 -
教師表:
教師工號 教師姓名 1 王老師 2 李老師 -
選課表:
學生ID 課程ID 教師工號 1 101 1 2 101 1 1 102 2 3 102 2
通過拆分,教師工號 → 教師姓名 的依賴關系被轉移到 教師表,而不再出現在原始的表中,從而使表符合 BCNF。
5. 第四范式(4NF)
定義:
一個表滿足 第四范式(4NF),要求:
- 必須滿足 BCNF。
- 表中不存在多值依賴(multivalued dependency)。
多值依賴 是指一個屬性集決定了兩個或多個其他屬性集,但這些屬性集之間沒有關系。例如,一個學生可以同時選修多門課程,并且每個學生有多個興趣愛好,這就構成了多值依賴。
通俗來說:
- 如果一個表中存在兩組不相關的多值依賴關系,那么表就不符合 4NF。
- 4NF 的目的是消除由于多值依賴引起的數據冗余。
4NF 示例:
假設有一個表記錄了學生的選修課程和興趣愛好:
學生ID | 選修課程 | 興趣愛好 |
---|---|---|
1 | 數學 | 籃球 |
1 | 英語 | 游泳 |
2 | 物理 | 籃球 |
在這個表中,學生ID 可以決定 選修課程 和 興趣愛好,但這兩個屬性集是獨立的,即學生選修課程與學生興趣愛好之間沒有直接關系。因此,表格存在 多值依賴,這是不符合 4NF 的。
解決方案:
為了滿足 4NF,我們需要將表拆分為兩個表:
- 一個記錄學生和選修課程的表。
- 一個記錄學生和興趣愛好的表。
拆分后的表:
-
學生課程表:
學生ID 選修課程 1 數學 1 英語 2 物理 -
學生興趣表:
學生ID 興趣愛好 1 籃球 1 游泳 2 籃球
這樣,兩個獨立的多值依賴關系被拆分到不同的表中,消除了冗余數據,符合 4NF。
6. 第五范式(5NF)
定義:
一個表滿足 第五范式(5NF),要求:
- 必須滿足 4NF。
- 表中不存在任何連接依賴(join dependency)。
連接依賴 是指表中的某些數據不能通過簡單的連接來表示,而是需要一些特殊的處理邏輯來恢復數據。這通常發生在多對多關系中的某些復雜數據模式下。
通俗來說:
- 5NF 關注的是 連接依賴,要求每個數據表的拆分是合理的,且所有的拆分都應該能夠通過連接操作恢復。
- 它的主要目的是消除由于復雜多對多關系引起的冗余。
5NF 示例:
假設有一個表記錄了員工、項目和技能的信息:
員工ID | 項目ID | 技能 |
---|---|---|
1 | 101 | 編程 |
1 | 101 | 設計 |
1 | 102 | 編程 |
2 | 101 | 設計 |
2 | 102 | 編程 |
在這個表中,員工ID、項目ID 和 技能 之間存在復雜的多對多關系。為了保持 5NF,我們需要拆分表格,以便每個表只描述一個單一的多對多關系。
拆分后的表:
- 員工項目表:
員工ID 項目ID 1 101 1 102 2 101 2 102 - 員工技能表:
員工ID 技能 1 編程 1 設計 2 設計 2 編程 - 項目技能表:
項目ID 技能 101 編程 101 設計 102 編程
這樣,表格被拆分后,可以通過連接操作恢復所有數據,且不存在任何連接依賴,符合 5NF。
7. 記憶法
1. 使用簡化的口訣或記憶法
記憶順序:
1NF → 2NF → 3NF → BCNF → 4NF → 5NF
記住每個范式的核心概念及其解決的問題:
- 1NF:原子性(數據不能重復,必須是單一值)。
- 2NF:消除部分依賴(每個非主屬性都必須完全依賴于主鍵)。
- 3NF:消除傳遞依賴(非主屬性不能依賴于其他非主屬性)。
- BCNF:每個決定因素都是候選鍵(更嚴格的3NF)。
- 4NF:消除多值依賴(避免兩個不相關屬性集之間的依賴)。
- 5NF:消除連接依賴(表拆分后可通過連接恢復,避免復雜的連接依賴)。
記憶法:
“原子完全傳遞候選,多值連接" —— 用來記住每個范式的解決問題:
- 原子:1NF(原子性)
- 完全:2NF(完全依賴)
- 傳遞:3NF(傳遞依賴)
- 候選:BCNF(候選鍵)
- 多值:4NF(多值依賴)
- 連接:5NF(連接依賴)
2. 關聯實例,逐步拆解
通過實例化的方式逐步理解和記憶每個范式的含義。先從一個實際的、帶有冗余問題的表開始,逐步通過范式的規范化過程來消除問題。
例如,使用一個簡單的表來說明每個范式:
- 1NF:學生ID、課程名、教師信息一行一值,不允許多值列。
- 2NF:從1NF拆解出來,解決了“學生姓名”只依賴“學生ID”這個部分依賴。
- 3NF:從2NF拆解出來,解決了“教師姓名”通過“教師工號”傳遞依賴的問題。
- BCNF:更嚴格的要求,消除“教師工號”決定“教師姓名”的問題。
- 4NF:解決了多個獨立的多值依賴,學生可以選修多個課程,也可以有多個興趣愛好,避免這些屬性混雜在一起。
- 5NF:消除了復雜的連接依賴,保證了拆分表后能通過連接恢復完整數據。
3. 用簡短問題檢查范式
用一些快速的檢查問題來幫助判斷某個表是否符合某個范式:
- 1NF:每個字段是否只有一個值?
- 2NF:表是否有復合主鍵,并且非主屬性完全依賴于主鍵?
- 3NF:表中是否有非主屬性依賴于其他非主屬性?
- BCNF:是否所有決定其他屬性的字段都是候選鍵?
- 4NF:是否存在多個獨立的多值依賴?
- 5NF:是否所有表的拆分可以通過連接恢復,沒有連接依賴?