國內絕大多數院校用的王珊的《數據庫系統概論》這本教材,某些方面並無給出很詳細很明確的解釋,與實際應用聯繫不那麼緊密,你有這樣的疑問也是挺正常的。我教《數據庫原理》這門課有幾年了,有不少學生提出了和你同樣的問題,試着給你解釋一下吧。(基原本自於我上課的內容,某些地方爲了避免過於囉嗦,放棄了必定的嚴謹,主要是在「關係」和「表」上)數據庫
首先要明白」範式(NF)」是什麼意思。按照教材中的定義,範式是「符合某一種級別的關係模式的集合,表示一個關係內部各屬性之間的聯繫的合理化程度」。很晦澀吧?實際上你能夠把它粗略地理解爲一張數據表的表結構所符合的某種設計標準的級別。就像家裏裝修買建材,最環保的是E0級,其次是E1級,還有E2級等等。數據庫範式也分爲1NF,2NF,3NF,BCNF,4NF,5NF。通常在咱們設計關係型數據庫的時候,最多考慮到BCNF就夠。符合高一級範式的設計,一定符合低一級範式,例如符合2NF的關係模式,一定符合1NF。架構
接下來就對每一級範式進行一下解釋,首先是第一範式(1NF)。數據庫設計
符合1NF的關係(你能夠理解爲數據表。「關係模式」和「關係」的區別,相似於面向對象程序設計中」類「與」對象「的區別。」關係「是」關係模式「的一個實例,你能夠把」關係」理解爲一張帶數據的表,而「關係模式」是這張數據表的表結構。1NF的定義爲:符合1NF的關係中的每一個屬性都不可再分。表1所示的狀況,就不符合1NF的要求。ide
表1函數
實際上,1NF是全部關係型數據庫的最基本要求,你在關係型數據庫管理系統(RDBMS),例如SQL Server,Oracle,MySQL中建立數據表的時候,若是數據表的設計不符合這個最基本的要求,那麼操做必定是不能成功的。也就是說,只要在RDBMS中已經存在的數據表,必定是符合1NF的。若是咱們要在RDBMS中表現表中的數據,就得設計爲表2的形式:性能
表2學習
可是僅僅符合1NF的設計,仍然會存在數據冗餘過大,插入異常,刪除異常,修改異常的問題,例如對於表3中的設計:大數據
表3編碼
正由於僅符合1NF的數據庫設計存在着這樣那樣的問題,咱們須要提升設計標準,去掉致使上述四種問題的因素,使其符合更高一級的範式(2NF),這就是所謂的「規範化」。spa
第二範式(2NF)在關係理論中的嚴格定義我這裏就很少介紹了(由於涉及到的鋪墊比較多),只須要了解2NF對1NF進行了哪些改進便可。其改進是,2NF在1NF的基礎之上,消除了非主屬性對於碼的部分函數依賴。接下來對這句話中涉及到的四個概念——「函數依賴」、「碼」、「非主屬性」、與「部分函數依賴」進行一下解釋。
函數依賴
咱們能夠這麼理解(但並非特別嚴格的定義):若在一張表中,在屬性(或屬性組)X的值肯定的狀況下,一定能肯定屬性Y的值,那麼就能夠說Y函數依賴於X,寫做 X → Y。也就是說,在數據表中,不存在任意兩條記錄,它們在X屬性(或屬性組)上的值相同,而在Y屬性上的值不一樣。這也就是「函數依賴」名字的由來,相似於函數關係 y = f(x),在x的值肯定的狀況下,y的值必定是肯定的。
例如,對於表3中的數據,找不到任何一條記錄,它們的學號相同而對應的姓名不一樣。因此咱們能夠說姓名函數依賴於學號,寫做 學號 → 姓名。可是反過來,由於可能出現同名的學生,因此有可能不一樣的兩條學生記錄,它們在姓名上的值相同,但對應的學號不一樣,因此咱們不能說學號函數依賴於姓名。表中其餘的函數依賴關係還有如:
但如下函數依賴關係則不成立:
從「函數依賴」這個概念展開,還會有三個概念:
徹底函數依賴
在一張表中,若 X → Y,且對於 X 的任何一個真子集(假如屬性組 X 包含超過一個屬性的話),X ' → Y 不成立,那麼咱們稱 Y 對於 X 徹底函數依賴,記做 X F→ Y。(那個F應該寫在箭頭的正上方,沒辦法打出來……,正確的寫法如圖1)
圖1
例如:
部分函數依賴
假如 Y 函數依賴於 X,但同時 Y 並不徹底函數依賴於 X,那麼咱們就稱 Y 部分函數依賴於 X,記做 X P→ Y,如圖2。
圖2
例如:
傳遞函數依賴
假如 Z 函數依賴於 Y,且 Y 函數依賴於 X (感謝
圖3
碼
設 K 爲某表中的一個屬性或屬性組,若除 K 以外的全部屬性都徹底函數依賴於 K(這個「徹底」不要漏了),那麼咱們稱 K 爲候選碼,簡稱爲碼。在實際中咱們一般能夠理解爲:假如當 K 肯定的狀況下,該表除 K 以外的全部屬性的值也就隨之肯定,那麼 K 就是碼。一張表中能夠有超過一個碼。(實際應用中爲了方便,一般選擇其中的一個碼做爲主碼)
例如:
對於表3,(學號、課名)這個屬性組就是碼。該表中有且僅有這一個碼。(假設全部課沒有重名的狀況)
非主屬性
包含在任何一個碼中的屬性成爲主屬性。
例如:
對於表3,主屬性就有兩個,學號 與 課名。
終於能夠回過來看2NF了。首先,咱們須要判斷,表3是否符合2NF的要求?根據2NF的定義,判斷的依據實際上就是看數據表中是否存在非主屬性對於碼的部分函數依賴。若存在,則數據表最高只符合1NF的要求,若不存在,則符合2NF的要求。判斷的方法是:
第一步:找出數據表中全部的碼。
第二步:根據第一步所獲得的碼,找出全部的主屬性。
第三步:數據表中,除去全部的主屬性,剩下的就都是非主屬性了。
第四步:查看是否存在非主屬性對碼的部分函數依賴。
對於表3,根據前面所說的四步,咱們能夠這麼作:
第一步:
看起來很麻煩是吧,可是這裏有一個訣竅,就是假如A是碼,那麼全部包含了A的屬性組,如(A,B)、(A,C)、(A,B,C)等等,都不是碼了(由於做爲碼的要求裏有一個「徹底函數依賴」)。
圖4表示了表中全部的函數依賴關係:
圖4
這一步完成之後,能夠獲得,表3的碼只有一個,就是(學號、課名)。
第二步:
主屬性有兩個:學號 與 課名
第三步:
非主屬性有四個:姓名、系名、系主任、分數
第四步:
對於(學號,課名) → 姓名,有 學號 → 姓名,存在非主屬性 姓名 對碼(學號,課名)的部分函數依賴。
對於(學號,課名) → 系名,有 學號 → 系名,存在非主屬性 系名 對碼(學號,課名)的部分函數依賴。
對於(學號,課名) → 系主任,有 學號 → 系主任,存在非主屬性 對碼(學號,課名)的部分函數依賴。
因此表3存在非主屬性對於碼的部分函數依賴,最高只符合1NF的要求,不符合2NF的要求。
爲了讓表3符合2NF的要求,咱們必須消除這些部分函數依賴,只有一個辦法,就是將大數據表拆分紅兩個或者更多個更小的數據表,在拆分的過程當中,要達到更高一級範式的要求,這個過程叫作」模式分解「。模式分解的方法不是惟一的,如下是其中一種方法:
選課(學號,課名,分數)
學生(學號,姓名,系名,系主任)
咱們先來判斷如下,選課表與學生表,是否符合了2NF的要求?
對於選課表,其碼是(學號,課名),主屬性是學號和課名,非主屬性是分數,學號肯定,並不能惟一肯定分數,課名肯定,也不能惟一肯定分數,因此不存在非主屬性分數對於碼 (學號,課名)的部分函數依賴,因此此表符合2NF的要求。
對於學生表,其碼是學號,主屬性是學號,非主屬性是姓名、系名和系主任,由於碼只有一個屬性,因此不可能存在非主屬性對於碼 的部分函數依賴,因此此表符合2NF的要求。
圖5表示了模式分解之後的新的函數依賴關係
圖5
表4表示了模式分解之後新的數據
表4
(這裏還涉及到一個如何進行模式分解纔是正確的知識點,先不介紹了)
如今咱們來看一下,進行一樣的操做,是否還存在着以前的那些問題?
因此說,僅僅符合2NF的要求,不少狀況下仍是不夠的,而出現問題的緣由,在於仍然存在非主屬性系主任對於碼學號的傳遞函數依賴。爲了能進一步解決這些問題,咱們還須要將符合2NF要求的數據表改進爲符合3NF的要求。
第三範式(3NF) 3NF在2NF的基礎之上,消除了非主屬性對於碼的傳遞函數依賴。也就是說, 若是存在非主屬性對於碼的傳遞函數依賴,則不符合3NF的要求。
接下來咱們看看錶4中的設計,是否符合3NF的要求。
對於選課表,主碼爲(學號,課名),主屬性爲學號和課名,非主屬性只有一個,爲分數,不可能存在傳遞函數依賴,因此選課表的設計,符合3NF的要求。
對於學生表,主碼爲學號,主屬性爲學號,非主屬性爲姓名、系名和系主任。由於 學號 → 系名,同時 系名 → 系主任,因此存在非主屬性系主任對於碼學號的傳遞函數依賴,因此學生表的設計,不符合3NF的要求。。
爲了讓數據表設計達到3NF,咱們必須進一步進行模式分解爲如下形式:
選課(學號,課名,分數)
學生(學號,姓名,系名)
系(系名,系主任)
對於選課表,符合3NF的要求,以前已經分析過了。
對於學生表,碼爲學號,主屬性爲學號,非主屬性爲系名,不可能存在非主屬性對於碼的傳遞函數依賴,因此符合3NF的要求。
對於系表,碼爲系名,主屬性爲系名,非主屬性爲系主任,不可能存在非主屬性對於碼的傳遞函數依賴(至少要有三個屬性纔可能存在傳遞函數依賴關係),因此符合3NF的要求。。
新的函數依賴關係如圖6
圖6
新的數據表如表5
表5
如今咱們來看一下,進行一樣的操做,是否還存在着以前的那些問題?
結論
因而可知,符合3NF要求的數據庫設計,基本上解決了數據冗餘過大,插入異常,修改異常,刪除異常的問題。固然,在實際中,每每爲了性能上或者應對擴展的須要,常常 作到2NF或者1NF,可是做爲數據庫設計人員,至少應該知道,3NF的要求是怎樣的。
==============時隔半年,終於決定把這個坑填上,來晚了 ===========
BCNF範式
要了解 BCNF 範式,那麼先看這樣一個問題:
若:
那麼關係模式 倉庫(倉庫名,管理員,物品名,數量) 屬於哪一級範式?
答:已知函數依賴集:倉庫名 → 管理員,管理員 → 倉庫名,(倉庫名,物品名)→ 數量
碼:(管理員,物品名),(倉庫名,物品名)
主屬性:倉庫名、管理員、物品名
非主屬性:數量
∵ 不存在非主屬性對碼的部分函數依賴和傳遞函數依賴。∴ 此關係模式屬於3NF。
基於此關係模式的關係(具體的數據)可能如圖所示:
好,既然此關係模式已經屬於了 3NF,那麼這個關係模式是否存在問題呢?咱們來看如下幾種操做:
從這裏咱們能夠得出結論,在某些特殊狀況下,即便關係模式符合 3NF 的要求,仍然存在着插入異常,修改異常與刪除異常的問題,仍然不是 」好「 的設計。
形成此問題的緣由:存在着主屬性對於碼的部分函數依賴與傳遞函數依賴。(在此例中就是存在主屬性【倉庫名】對於碼【(管理員,物品名)】的部分函數依賴。
解決辦法就是要在 3NF 的基礎上消除主屬性對於碼的部分與傳遞函數依賴。
倉庫(倉庫名,管理員)
庫存(倉庫名,物品名,數量)
這樣,以前的插入異常,修改異常與刪除異常的問題就被解決了。
以上就是關於 BCNF 的解釋。
最近身體不太舒服,寫不動了。有空再放幾個典型習題及其解答吧。
===============================
問題1:
李德竹 :老師您好,我看了您關於數據庫範式的回答,有一點不太理解,就是關於碼的定義,若是除K以外的全部屬性都徹底函數依賴於K時才能稱K爲碼,那麼在判斷2NF時又怎麼會存在非主屬性對碼的部分函數依賴這種狀況?但願老師有時間能指點一下,謝謝
我 :在「碼」的定義中,除 K 以外的全部屬性應該當作是一個集合 U(也就是一個總體),也就是說,只有 K 可以徹底函數決定 U 中的每個屬性,那麼 K 纔是碼。若是 K 只是可以徹底函數決定 U 中的一部分屬性,而不能徹底函數決定另一部分屬性,那麼 K 不是碼。
好比有關係模式 R (Sno, Sname, Cno, Cname, Sdept, Sloc, Grade),其中函數依賴集爲 F= {
Sno → Sname, Sno → Sdept, Sdept → Sloc,Sno → Sloc, Cno → Cname, (Sno, Cno) → Grade }
那麼 R 中的碼只能是 (Sno, Cno),Sno 或 Cno 並不能徹底函數決定除 Sno / Cno 以外的全部其餘屬性(其實就是不能決定 Grade ),因此單獨的 Sno 與 Cno 並不能做爲碼。
因此可獲得主屬性:Sno, Cno
非主屬性:Sname, Cname, Sdept, Sloc, Grade
R 中存在非主屬性 Cname 對於碼 (Sno, Cno) 的部分函數依賴 (Cno → Cname) 。(還有不少別的例子就不一一列舉了)。因此 R 不符合 2NF 的要求。
========================================
花了好幾天斷斷續續寫了這個答案,累死我了。看有很多人對此有疑問,乾脆寫一個詳細點的,但願成爲這個知識點的權威回答……若是有一些細節方面的問題,好比表達上,還會進行修改,大的方面,確定是沒錯的。
謝邀。
這個問題不太好解釋,我盡力吧!
一範式就是屬性不可分割。屬性是什麼?就是表中的字段。
不可分割的意思就按字面理解就是最小單位,不能再分紅更小單位了。
這個字段只能是一個值,不能被拆分紅多個字段,不然的話,它就是可分割的,就不符合一範式。
不過能不能分割並無絕對的答案,看需求,也就是看你的設計目標而定。
舉例:
學生信息組成學生信息表,有姓名、年齡、性別、學號等信息組成。
姓名不可拆分吧?因此能夠做爲該表的一個字段。
但我要說這個表要在國外使用呢?人家姓和名要分開,都有特別的意義,因此姓名字段是可拆分的,分爲姓字段和名字段。
簡單來講,一範式是關係數據庫的基礎,但字段是否真的不可拆分,根據你的設計目標而定。
二範式就是要有主鍵,要求其餘字段都依賴於主鍵。
爲何要有主鍵?沒有主鍵就沒有惟一性,沒有惟一性在集合中就定位不到這行記錄,因此要主鍵。
其餘字段爲何要依賴於主鍵?由於不依賴於主鍵,就找不到他們。更重要的是,其餘字段組成的這行記錄和主鍵表示的是同一個東西,而主鍵是惟一的,它們只須要依賴於主鍵,也就成了惟一的。
若是有同窗不理解依賴這個詞,能夠勉強用「相關」這個詞代替,也就是說其餘字段必須和它們的主鍵相關。由於不相關的東西不該該放在一行記錄裏。
舉例:
學生信息組成學生表,姓名能夠作主鍵麼?
不能!由於同名的話,就不惟一了,因此須要學號這樣的惟一編碼才行。
那麼其餘字段依賴於主鍵是什麼意思?
就是「張三」同窗的年齡和性別等字段,不能存儲別人的年齡性別,必須是他本身的,由於張三的學號信息就決定了,這行記錄歸張三全部,不能給無關人員使用。
三範式就是要消除傳遞依賴,方便理解,能夠看作是「消除冗餘」。
消除冗餘應該比較好理解一些,就是各類信息只在一個地方存儲,不出如今多張表中。
好比說大學分了不少系(中文系、英語系、計算機系……),這個系別管理表信息有如下字段組成:
系編號,系主任,系簡介,系架構。
那麼再回到學生信息表,張三同窗的年齡、性別、學號都有了,我能不能把他的系編號,系主任、系簡介也一塊兒存着?
若是你問三範式,固然不行,由於三範式不一樣意。
由於系編號,系主任、系簡介已經存在系別管理表中,你再存入學生信息表,就是冗餘了。
三範式中說的傳遞依賴,就出現了。
這個時候學生信息表中,系主任信息是否是依賴於系編號了?而這個表的主鍵但是學號啊!
因此按照三範式,處理這個問題的時候,學生表就只能增長一個系編號字段。
這樣既能根據系編號找到系別信息,又避免了冗餘存儲的問題。
所謂的範式,是用來學習參考的,設計的時候根據狀況,未必必定要遵照,切記。
三範式都能碼這麼多字,我果真愈來愈水了:)