規范化理論
1.數據依賴
數據依賴是一個關系內部屬性和屬性之間的一種約束。這種約束關系是通過屬性間值的相等與否體現出來的一種關聯關系,是現實語義的體現。其類型包括函數依賴(Function Dependency,FD)和多值依賴(Multi-Valued Dependency,MVD)。
什么是函數依賴?
比如描述一個學生關系,可以有學號(Sno)、姓名(Sname)、系別(Sdept)等屬性。由於一個學號只對應一個學生,一個學生只對應一個系,因此,學號確定后,則對應的姓名和系別也唯一的確定了。可記作:Sno→Sname,Sno→Sdept。即屬性X確定后,屬性Y也唯一的確定了(稱為X確定Y,或Y依賴X),用數學語言描述,即存在函數關系f,y=f(x)。或者,換句話說,不存在兩個元組在屬性X上的值相等而在屬性Y的值不等,這就是函數依賴。
示例:有這么一個學校教務的數據庫,涉及學生的學號(Sno)、所在系別(Sdept)、系主任名字(Mname)、課程號(Cno)和成績(Grade)。根據現實語義,可以有這樣的函數依賴關系:
F = {Sno→Sdept,Sdept→Mname,(Sno, Cno)→Grade}
完全函數依賴?
(Sno, Cno)→Grade 就是完全函數依賴,因為屬性Grade完全函數依賴於Sno和Cno,少一個屬性都不行。
部分函數依賴?
(Sno, Cno)→Sdept 就是部分函數依賴,因為對於屬性Sdept,由單個屬性Sno就已經可以確定了,即Sno→Sdept,而Sno是(Sno, Cno)子集。
傳遞函數依賴?
簡單的講,因為Sno→Sdept,且Sdept→Mname,所以可以得出Sno→Mname,這就是傳遞函數依賴。(這樣描述其實不夠嚴謹,但不妨礙理解)
什么是候選碼/主碼/碼?
關系中的某個屬性或者某幾個屬性的組合,用於區分每個元組,稱為候選碼。所謂“區分元組”,就是指當一個元組的候選碼確定了,則元組中的其他屬性也就確定了,且不同元組的候選碼一定是不同的!如果一個元組有多個候選碼,則一般選取其中一個作為主碼。在使用中,常常把候選碼和主碼都簡稱為碼。此外,包含在碼中的屬性稱為主屬性,不包含在碼中的屬性稱為非主屬性。
2.范式(Normal Form,NF)
范式是“符合某一種級別的關系模式的集合,表示一個關系內部各屬性之間的聯系的合理化程度”。我們可以把它粗略地理解為一張數據表的表結構所符合的某種設計標准的級別。就像家里裝修買建材,最環保的是E0級,其次是E1級,還有E2級等等。數據庫范式也分為1NF,2NF,3NF,BCNF,4NF,5NF。一般在我們設計關系型數據庫的時候,最多考慮到BCNF就夠。符合高一級范式的設計,必定符合低一級范式,例如符合2NF的關系模式,必定符合1NF。
1NF:在一個關系中,屬性不可再分。即不允許表中有表。
第一范式(1NF)是所有關系型數據庫的最基本要求,但僅僅符合1NF的設計,很可能會出現數據冗余、更新復雜、插入異常、刪除異常的問題。例如下面這張表:
存在如下幾個問題:
- 學號、姓名、系名、系主任等信息重復多次,出現的次數與(學號,課名)出現的次數一致——數據冗余。
- 由於數據冗余,當需要更新數據時,代價昂貴。比如,現在某系的系主任換了,則與之有關的所有記錄都得更新——更新復雜。
- 假如一個系剛成立(系名、系主任的信息有了),還沒有招生(學號、姓名的信息沒有),則無法插入數據——插入異常。
- 根據碼的概念,該表中,碼應該為(學號,課名),根據實體完整性約束,插入一條新的記錄時主碼不能為空,所以不能插入
- 假如將某個系中所有學生相關的記錄都刪除,那么所有系與系主任的數據也就隨之消失了(假如一個系所有學生都畢業了,並不表示這個系就沒有了)——刪除異常。
2NF:在滿足1NF的基礎上,消除了非主屬性對候選碼的部分函數依賴,即要求每個非主屬性完全函數依賴於候選碼。
以上表為例,碼是(學號,課名),即主屬性是學號和課名,非主屬性是姓名、系名、系主任和分數。那么任意一個非主屬性對碼是完全函數依賴還是部分函數依賴呢?很顯然,屬性 姓名 對碼 (學號,課名) 就是部分函數依賴,因此,該表不符合2NF的要求。為了讓上表符合2NF的要求,我們必須消除這些部分函數依賴,只有一個辦法,就是將大數據表拆分成兩個或者更多個更小的數據表,在拆分的過程中,要達到更高一級范式的要求,這個過程叫做“模式分解”。模式分解的方法不是唯一的,以下是其中一種方法:
- 選課(學號,課名,分數)
- 學生(學號,姓名,系名,系主任)
我們先來判斷以下,選課表與學生表,是否符合了2NF的要求?
對於選課表,其碼是(學號,課名),主屬性是學號和課名,非主屬性是分數,學號確定,並不能唯一確定分數,課名確定,也不能唯一確定分數,所以不存在非主屬性分數對於碼 (學號,課名)的部分函數依賴,所以此表符合2NF的要求。
對於學生表,其碼是學號,主屬性是學號,非主屬性是姓名、系名和系主任,因為碼只有一個屬性,所以不可能存在非主屬性對於碼的部分函數依賴,所以此表符合2NF的要求。
分解后的表如下:
那么,對於1NF中的表,該表是否有改進呢?(與前面的一一對應)
- 姓名、系別、系主任的冗余程度明顯減少了。(有改進)
- 由於冗余程度降低,那么更改的復雜度也降低了。(有改進)
- 若存在剛成立但還未招生的系,仍然無法插入數據。(無改進)
- 若刪除一個系的所有學生,那么該系的其他信息(系名、系主任)也被刪除了。(無改進)
3NF:在滿足2NF的基礎上,消除了非主屬性對於候選碼的傳遞函數依賴。也就是說, 如果存在非主屬性對於碼的傳遞函數依賴,則不符合3NF的要求。
對於2NF中的表,我們根據3NF的要求,分析如下:
對於選課表,主碼為(學號,課名),主屬性為學號和課名,非主屬性只有一個,為分數,不可能存在傳遞函數依賴,所以選課表的設計,符合3NF的要求。
對於學生表,主碼為學號,主屬性為學號,非主屬性為姓名、系名和系主任。因為 學號→系名,且有系名→系主任,所以存在非主屬性(系主任)對於碼(學號)的傳遞函數依賴,所以學生表的設計,不符合3NF的要求。
為了讓數據表設計達到3NF,我們必須進一步進行模式分解為以下形式:
- 選課(學號,課名,分數)
- 學生(學號,姓名,系名)
- 系(系名,系主任)
對於選課表,符合3NF的要求,之前已經分析過了。
對於學生表,碼為學號,主屬性為學號,非主屬性為姓名和系名,不可能存在“學號→姓名 & 姓名→系名(因為同姓名的人是有很多噠)”,或是“學號→系名 & 系名→姓名”,所以符合3NF的要求。
對於系表,碼為系名,主屬性為系名,非主屬性為系主任,不可能存在非主屬性對於碼的傳遞函數依賴(至少要有三個屬性才可能存在傳遞函數依賴關系),所以符合3NF的要求。。
經過改進后,符合3NF要求的數據庫設計,基本解決了數據冗余、更新復雜、插入異常、刪除異常的不足。
BCNF:消除主屬性對碼的部分函數依賴和傳遞函數依賴。 (BCNF和4NF暫且不探究了,太難了。。。)
3.總結
在關系數據庫中,最基本的要求是滿足第一范式。但是,在一些表結構的設計中,會發現存在數據冗余、插入異常、刪除異常和修改復雜的問題,於是就要解決這些問題,這就是規范化的目的。從1NF到2NF,3NF...的演進,概括的說,就是把大表逐步拆分為小表的過程,逐步消除數據依賴中不合適的部分。所謂規范化的實質,就是概念的單一化。