解釋一下關係資料庫的第一第二第三範式?
第一範式不可分割?第三範式沒有傳遞依賴?沒看懂是什麼意思希望指點!
2015-1-9 更新,回答了 @李德竹 的問題
============
2015-1-6 更新,補充了 BCNF 的解釋
============
國內絕大多數院校用的王珊的《資料庫系統概論》這本教材,某些方面並沒有給出很詳細很明確的解釋,與實際應用聯繫不那麼緊密,你有這樣的疑問也是挺正常的。我教《資料庫原理》這門課有幾年了,有很多學生提出了和你一樣的問題,試著給你解釋一下吧。(基本來自於我上課的內容,某些地方為了不過於啰嗦,放棄了一定的嚴謹,主要是在「關係」和「表」上)
首先要明白」範式(NF)」是什麼意思。按照教材中的定義,範式是「符合某一種級別的關係模式的集合,表示一個關係內部各屬性之間的聯繫的合理化程度」。很晦澀吧?實際上你可以把它粗略地理解為一張數據表的表結構所符合的某種設計標準的級別。就像家裡裝修買建材,最環保的是E0級,其次是E1級,還有E2級等等。資料庫範式也分為1NF,2NF,3NF,BCNF,4NF,5NF。一般在我們設計關係型資料庫的時候,最多考慮到BCNF就夠。符合高一級範式的設計,必定符合低一級範式,例如符合2NF的關係模式,必定符合1NF。
接下來就對每一級範式進行一下解釋,首先是第一範式(1NF)。
符合1NF的關係(你可以理解為數據表。「關係模式」和「關係」的區別,類似於面向對象程序設計中」類「與」對象「的區別。」關係「是」關係模式「的一個實例,你可以把」關係」理解為一張帶數據的表,而「關係模式」是這張數據表的表結構。1NF的定義為:符合1NF的關係中的每個屬性都不可再分。表1所示的情況,就不符合1NF的要求。
表1
實際上,1NF是所有關係型資料庫的最基本要求,你在關係型資料庫管理系統(RDBMS),例如SQL Server,Oracle,MySQL中創建數據表的時候,如果數據表的設計不符合這個最基本的要求,那麼操作一定是不能成功的。也就是說,只要在RDBMS中已經存在的數據表,一定是符合1NF的。如果我們要在RDBMS中表現表中的數據,就得設計為表2的形式:
表2
但是僅僅符合1NF的設計,仍然會存在數據冗餘過大,插入異常,刪除異常,修改異常的問題,例如對於表3中的設計:
表3
- 每一名學生的學號、姓名、系名、系主任這些數據重複多次。每個系與對應的系主任的數據也重複多次——數據冗餘過大
- 假如學校新建了一個系,但是暫時還沒有招收任何學生(比如3月份就新建了,但要等到8月份才招生),那麼是無法將系名與系主任的數據單獨地添加到數據表中去的 (注1)——插入異常
注1:根據三種關係完整性約束中實體完整性的要求,關係中的碼(注2)所包含的任意一個屬性都不能為空,所有屬性的組合也不能重複。為了滿足此要求,圖中的表,只能將學號與課名的組合作為碼,否則就無法唯一地區分每一條記錄。
注2:碼:關係中的某個屬性或者某幾個屬性的組合,用於區分每個元組(可以把「元組」理解為一張表中的每條記錄,也就是每一行)。
- 假如將某個系中所有學生相關的記錄都刪除,那麼所有系與系主任的數據也就隨之消失了(一個系所有學生都沒有了,並不表示這個系就沒有了)。——刪除異常
- 假如李小明轉繫到法律系,那麼為了保證資料庫中數據的一致性,需要修改三條記錄中系與系主任的數據。——修改異常。
正因為僅符合1NF的資料庫設計存在著這樣那樣的問題,我們需要提高設計標準,去掉導致上述四種問題的因素,使其符合更高一級的範式(2NF),這就是所謂的「規範化」。
第二範式(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
例如:
- 學號 F→ 姓名
- (學號,課名) F→ 分數 (註:因為同一個的學號對應的分數不確定,同一個課名對應的分數也不確定)
部分函數依賴
假如 Y 函數依賴於 X,但同時 Y 並不完全函數依賴於 X,那麼我們就稱 Y 部分函數依賴於 X,記作 X P→ Y,如圖2。
圖2
例如:
- (學號,課名) P→ 姓名
傳遞函數依賴
假如 Z 函數依賴於 Y,且 Y 函數依賴於 X (感謝 @百達 指出的錯誤,這裡改為:『Y 不包含於 X,且 X 不函數依賴於 Y』這個前提),那麼我們就稱 Z 傳遞函數依賴於 X ,記作 X T→ Z,如圖3。
圖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 的要求。
========================================
花了好幾天斷斷續續寫了這個答案,累死我了。看有不少人對此有疑問,乾脆寫一個詳細點的,希望成為這個知識點的權威回答……如果有一些細節方面的問題,比如表達上,還會進行修改,大的方面,肯定是沒錯的。
謝邀。
這個問題不太好解釋,我儘力吧!
一範式就是屬性不可分割。屬性是什麼?就是表中的欄位。
不可分割的意思就按字面理解就是最小單位,不能再分成更小單位了。
這個欄位只能是一個值,不能被拆分成多個欄位,否則的話,它就是可分割的,就不符合一範式。
不過能不能分割並沒有絕對的答案,看需求,也就是看你的設計目標而定。
舉例:
學生信息組成學生信息表,有姓名、年齡、性別、學號等信息組成。
姓名不可拆分吧?所以可以作為該表的一個欄位。
但我要說這個表要在國外使用呢?人家姓和名要分開,都有特別的意義,所以姓名欄位是可拆分的,分為姓欄位和名欄位。
簡單來說,一範式是關係資料庫的基礎,但欄位是否真的不可拆分,根據你的設計目標而定。
二範式就是要有主鍵,要求其他欄位都依賴於主鍵。
為什麼要有主鍵?沒有主鍵就沒有唯一性,沒有唯一性在集合中就定位不到這行記錄,所以要主鍵。
其他欄位為什麼要依賴於主鍵?因為不依賴於主鍵,就找不到他們。更重要的是,其他欄位組成的這行記錄和主鍵表示的是同一個東西,而主鍵是唯一的,它們只需要依賴於主鍵,也就成了唯一的。
如果有同學不理解依賴這個詞,可以勉強用「相關」這個詞代替,也就是說其他欄位必須和它們的主鍵相關。因為不相關的東西不應該放在一行記錄里。
舉例:
學生信息組成學生表,姓名可以做主鍵么?
不能!因為同名的話,就不唯一了,所以需要學號這樣的唯一編碼才行。
那麼其他欄位依賴於主鍵是什麼意思?
就是「張三」同學的年齡和性別等欄位,不能存儲別人的年齡性別,必須是他自己的,因為張三的學號信息就決定了,這行記錄歸張三所有,不能給無關人員使用。
三範式就是要消除傳遞依賴,方便理解,可以看做是「消除冗餘」。
消除冗餘應該比較好理解一些,就是各種信息只在一個地方存儲,不出現在多張表中。
比如說大學分了很多系(中文系、英語系、計算機系……),這個系別管理表信息有以下欄位組成:
系編號,系主任,系簡介,系架構。
那麼再回到學生信息表,張三同學的年齡、性別、學號都有了,我能不能把他的系編號,系主任、系簡介也一起存著?
如果你問三範式,當然不行,因為三範式不同意。
因為系編號,系主任、系簡介已經存在系別管理表中,你再存入學生信息表,就是冗餘了。
三範式中說的傳遞依賴,就出現了。
這個時候學生信息表中,系主任信息是不是依賴於系編號了?而這個表的主鍵可是學號啊!
所以按照三範式,處理這個問題的時候,學生表就只能增加一個系編號欄位。
這樣既能根據系編號找到系別信息,又避免了冗餘存儲的問題。
所謂的範式,是用來學習參考的,設計的時候根據情況,未必一定要遵守,切記。
三範式都能碼這麼多字,我果然越來越水了:)搬運工覺得這個講解對於初步學習的人比較好。
資料庫範式那些事
總結:
1NF: 欄位是最小的的單元不可再分
2NF:滿足1NF,表中的欄位必須完全依賴於全部主鍵而非部分主鍵 (一般我們都會做到)
3NF:滿足2NF,非主鍵外的所有欄位必須互不依賴
4NF:滿足3NF,消除表中的多值依賴
作為一個剛考完資料庫的人,來分享一下自己的見解。
NF(normal form)作為一個資料庫設計里經常會提到的概念,是每一個初學者都應該了解並掌握的。複習資料庫的時候發現 Database System Concepts 這本書里講的過於抽象,而且網上也沒有特別好的講解,於是自己重新整理一份,有需者自取。
NF的意義Normal form作為設計的標準範式,其最大的意義就是為了避免數據的冗餘和插入/刪除/更新的異常。舉個例子
表1
school(stu-id,stu-name,major,dean-name,dean-telephone)
在學校這個表裡面,學生的學號、姓名、專業、系主任以及系主任電話被放到了一起(典型的excel風格)。雖然這樣有些時候也不是不可以,但當進行一些特定操作的時候,著實會給我們帶來極大的困擾。
- 插入異常[ 輸入新信息的時候,系主任電話號碼輸錯 ] : 無法確認系主任的真正號碼。
- 刪除異常[ 某個系的學生全部退學了 ] : 該系對應的系主任名字和電話號碼也隨之丟失。
- 更新異常[ 系主任進行變更 / 系主任換手機號 ] : 我們需要把系裡所有學生的行都給更新一遍,顯然開銷過大。
1NF
定義:所有的屬性均有原子性
說人話:所有的屬性均不可被再分割,國外比較喜歡拿人名來舉例(first,middle,last),但跟國內國情不太符合,我就舉一個商品的例子好了。
TaobaoPucharsedLog(sid, date, buyer, seller, goods,amount)
顯然「商品」會有更多詳細的屬性,例如商品名稱,商品價格,產地等等。「用戶」也有昵稱,年齡,住址等,「商戶」也是如此。這些屬性都是可以再分割的,所以並不符合1NF範式,需要將其完全拆至不可分割為止。
修改示範:
TaobaoPucharsedLog(sid, date, buyer-id, buyer-name, buyer-age, seller, goods, amount) [僅拆開了buyer]
意義:嗯.. 這個還是等我們講完四個定理再來說吧,現在講解比較困難。
2NF(在滿足1NF的前提上)定義:如果依賴於主鍵,則需要依賴於所有主鍵,不能存在依賴部分主鍵的情況
說人話:對於上面那個例子,TaobaoPucharsedLog(sid, date, buyer-id, buyer-name, buyer-age, seller-id, seller-name, seller-age, goods-id, goods-name, amount)。可以看到裡面有四個主鍵:sid, buyer-id, seller-id, goods-id。對於seller-name屬性,它僅依賴於seller-id,跟buyer-id之類的沒有任何關係,所以它對於主鍵的依賴是「部分依賴」,並不符合2NF。簡單點說,就是不要把不相關的東西放到一個表裡面。
修改示範:
拆解成以下四個
- TaobaoPucharsedLog(sid, buyer-id, seller-id, goods-id, amount)
- BuyerInformation(buyer-id, buyer-name, buyer-age)
- SellerInformation(seller-id, seller-name, seller-age)
- GoodsInformation(goods-id, goods-name)
意義:不相關的東西不要放在一起,用多個小表連接來代替大表,減少修改時候的負擔。
3NF(在滿足1NF和2NF的前提上)定義:一個資料庫表中不包含已在其它表中已包含的非主關鍵字信息。
說人話:不得存在傳遞式依賴,比如對於一張資料庫,裡面的元素有son, person, father, grand-father,依賴關係是son -&> person, person -&> father, father -&> grand-father,明顯有一個鏈表式的傳遞,3NF中禁止此類依賴的出現。
修改示範:
依賴關係修改為
- son -&> person
- son -&> father
- son -&> grand-father
或者是拆成三張表
(其實就是並查集裡面的路徑壓縮)
意義:避免查詢路徑過長而導致詢問時間過長或者更新異常。以上面的家族關係為例,如果我想查詢某位同學曾曾曾曾曾……曾祖父是誰,按照非3NF的依賴,則需要進行多次查詢,而對於滿足3NF的依賴,只需要進行一次查詢。效率大大提高。
===待續==
.. 發現了點問題,
等我碼完通識課論文再回來慢慢更新
----------10.29日更新------------
有同學私信,問
『如何理解關係資料庫第一範式指導原則中的「關係中的每個數組必須包含相同數量的值」這一條』
- 數據組的每個屬性只能包含一個值;
- 關係中的每個數組必須包含相同數量的值;
- 關係中的每個數組一定不能相同。
個人認為太難理解,《Access 2003資料庫原理與應用標準教程》的描述更好理解一些
- 記錄的每個屬性只能包含一個值
- 關係中的每個記錄必須包含相同數量的值
- 關係中的每個記錄一定不能相同
第一條原則和第三條原則都不難理解
第二條舉個反例,看後就能理解
完。
----------以下為原文-------------
給個簡潔的判斷方法:
1NF:每個數據項都是最小單元,不可分割,其實就是確定行列之後只能對應一個數據,形象點就是你不對Exel作拆分單元格。 其實資料庫管理系統生成的最起碼也是第一範式。
2NF:非主屬性不部分依賴於候選碼
3NF:非主屬性不傳遞依賴於候選碼
BCNF:在滿足第二第三範式的情況下,主屬性內部也不能部分或傳遞依賴。判斷方法:箭頭左邊的必須是候選碼,不是候選碼的就不是BC範式。
4NF 沒有多值依賴
推薦觀看慕課網裡面的《資料庫設計那些事兒》
第一範式
- 第一範式(1NF)要求資料庫表的每一列都是不可分割的基本數據項,同一列中不能有多個值。
- 若某一列有多個值,可以將該列單獨拆分成一個實體,新實體和原實體間是一對多的關係。
- 在任何一個關係資料庫中,第一範式(1NF)是對關係模式的基本要求,不滿足第一範式(1NF)的資料庫就不是關係資料庫。
第二範式
- 滿足第二範式(2NF)必須先滿足第一範式(1NF)。
- 第二範式要求實體中沒一行的所有非主屬性都必須完全依賴於主鍵;即:非主屬性必須完全依賴於主鍵。
- 完全依賴:主鍵可能由多個屬性構成,完全依賴要求不允許存在非主屬性依賴於主鍵中的某一部分屬性。
- 若存在哪個非主屬性依賴於主鍵中的一部分屬性,那麼要將發生部分依賴的這一組屬性單獨新建一個實體,並且在舊實體中用外鍵與新實體關聯,並且新實體與舊實體間是一對多的關係。
第三範式
- 滿足第三範式必須先滿足第二範式。
- 第三範式要求:實體中的屬性不能是其他實體中的非主屬性。因為這樣會出現冗餘。即:屬性不依賴於其他非主屬性。
- 如果一個實體中出現其他實體的非主屬性,可以將這兩個實體用外鍵關聯,而不是將另一張表的非主屬性直接寫在當前表中。
看完各路大神的答案後頓有所悟,總結如下:
1.先要知道幾個概念:
碼:一個表中,可以唯一決定一個元組的屬性「集合」。而主鍵則是可以唯一決定元組的『某個屬性』。
例如:在成績表中(學號,課程號)合起來叫一個碼,而分開看學號是主鍵,課程號也是主鍵。
非主屬性:不屬於碼的屬性。
主屬性:屬於碼的屬性。
候選鍵:指每個都不一樣的、非空的那幾個屬性,有著潛在的主鍵意義。
比如一個表中的課程號學號,系別號等等。。
2.通俗的講範式:
1)第一範式:屬性不可拆分。
如:地址這個屬性是可拆分成城市地區等等,不可以把地址作為一個屬性
解決方案:屬性拆分開來,將一個地址屬性改成多個屬性,按照城市地區..設置多個屬性。
2)第二範式:每個表中的非主屬性完全依賴於碼。
特殊情況:若碼只有一個屬性,則必滿足第二範式。
如:(學號,課程號)這個表中的碼被「學生名字」部分函數依賴。即包含有學號→學生名字這種依賴關係。不符合2NF
解決方案:將部分函數依賴的部分碼和依賴這些碼的屬性拿出來單獨成表,在原表中用外鍵代替以前的多個屬性。
個人理解:將部分單獨拿出來,用一個外鍵在原表中代替,可以大大減少原表中的屬性條數。
3)第三範式:消除非主屬性之間的依賴關係,只保留非主屬性與碼的依賴關係。
(消除傳遞函數依賴的另一說法,本質是一樣的)
如:學號,課程號,系別,系主任。系別和系主任是非主屬性,學號和課程號是主屬性。但是系別和系主任這兩個非主屬性之間有函數依賴關係:系別→系主任。必造成傳函依賴:學號→系別→系主任。不符合3NF
解決方案:將這個非主屬性與其依賴的碼都拿出來單獨建表,並設置被依賴的屬性為主鍵,在原表中則用外鍵表示。
個人理解:將相互內在關聯的非主屬性用一個外鍵在原表中表示,可以大大減少數據冗餘。
4)BC範式:每個表中只有一個候選鍵。
如:學號,學生名字,學生QQ。我們設置學號作主鍵,但是學生QQ、學號這兩個都是候選鍵,一張表中有多個候選鍵,不符合BC範式。
解決方案:保留一個候選鍵作為主鍵,拿出其他的候選鍵單獨成表,將原表中的主鍵放入該表中。在原表中不顯示這個拿出來的候選鍵,從而 保證每個表中只有1個候選鍵。
個人理解:主鍵越少越好。一個表中的候選鍵越少越好。
但是這個BC範式有些苛刻了,很多情況比如成績單表(學生 課程 成績) ,學生、課程為候選鍵,我們這樣直接建表也是可以的。
設計到第三範式就行了!BC範式太苛刻了,大多數情況用不到。
三範式實際是很簡單的,真說幾句話就足夠。先假設你么已經看過最基本的定義。
如果換個方式來理解,這個問題就簡單了,表是對象的集合。
1NF, 欄位不可再分。這個關係資料庫強制了,想建立複合的欄位也建立不起來。關係資料庫出現之前才有這個問題。
2NF,主鍵依賴,就是一張表裡面的欄位,必須是跟主鍵相關的,不能把無關的數據放進來。主鍵依賴,實質就是,這個信息如果是對象的屬性,就放進來,否則就不放。
3NF,就是不能重複存儲相同的信息。這個情況,其實是在一個對象里引用了另外一個對象,這個時候,存一個引用就夠了,而不是重複的存儲這個對象的多個副本。
2NF和3NF的本質是,對象的屬性依賴對象。
資料庫的主鍵,作用是什麼?它用來唯一的標識這個對象,同時,用來給其他對象引用 引用 引用(重要的事情說三次)
所以,實戰中,所有資料庫都是用int類型做主鍵(int,或者bigint),而且,主鍵一律是自增,這是不成文的規則,凡是不遵守這個規則的,都是錯的(雖然理論上可以)
這樣,資料庫寫數據的時候,幾乎是永遠不寫入同一個對象的重複信息的,需要重複的時候,只寫這個對象的ID
比如,前面答案的這個圖,應該是這樣建表的(sql server 語法)
USE master
GO
if exists (select * from sysdatabases where name="mydb")
drop database mydb
go
create database mydb
go
go
create table Courses(
CourseID int identity primary key,
CourseName nvarchar(50) not null
);
create table Departments(
DepartmentID int identity primary key,
DepartmentName nvarchar(50) not null,
HeadName nvarchar(50) not null
);
create table Students(
StudentID int identity primary key,
Name nvarchar(50),
DepartmentID int not null
Constraint FkStudentDepartment foreign key (DepartmentID) references Departments(DepartmentID)
);
create table Results(
ResultID int identity primary key,
StudentID int not null,
CourseID int not null,
Result int not null,
Constraint FkResultStudent foreign key (StudentID) references Students(StudentID)
);
範式(Normal Form)是關係型資料庫正規化中的概念,用於減少資料庫中數據冗餘,增進數據的一致性。
1NF
表中的每個欄位都是最小的數據單元
例如,用戶信息中,「聯繫方式」欄位不應該為「手機+居住地址」,而是單獨作為兩個原子值欄位。否則當需要針對「手機」進行查詢時,不管是查詢性能和成本都是不理想的。
除此之外,每一條記錄需要有一個欄位以確定其唯一性。
2NF
在 1NF 的基礎上,表中所有的非碼屬性必須完全依賴於候選碼
「碼屬性(候選碼屬性)」 指能唯一標識一個元組的屬性,任何一個碼屬性都可以作為表的主鍵。
也就是說,「非碼屬性」不能由候選碼的某個部分所確定,否則應該把這個關係獨立為另一張表。
例如,某張表的主鍵由「學號」與「學院 ID」確定,那麼「學院名稱」就不應該出現在這張表裡,而是應該放到「學院」表中,否則就出現了數據冗餘,也不利於保持數據一致性。
3NF
在 2NF 的基礎上,非主屬性之間沒有相互依賴(消除傳遞依賴)
「傳遞依賴」是指,設 X,Y,Z 是關係 R 中互不相同的屬性集合,存在 X→Y(Y!→X),Y→Z,則稱 Z 傳遞函數依賴於 X。
例如某張表的外鍵包含「學院 ID」,則「學院名稱」不應該出現在這張表裡,因為「學院 ID」可以推導出「學院名稱」。
BCNF
在 3NF 的基礎上,沒有任何屬性完全函數依賴於非候選碼的任何一組屬性
3NF 不允許非主屬性被另一個非主屬性決定,但允許主屬性被非主屬性決定,而 BCNF 中,任何屬性(包括非主屬性和主屬性)都不能被非主屬性所決定。
4NF
在 BCNF 的基礎上,消除表中的多值依賴
「多值依賴」的定義為:設 R(U) 是屬性集 U 上的一個關係模式。X,Y,Z 是 U 的子集,並且 Z=U-X-Y。關係模式 R(U) 中多值依賴 X→→Y 成立,當且僅當對 R(U) 的任一關係 r,給定的一對 (x,z) 值有一組 Y 的值,這組值僅僅決定於 x 值而與 z 值無關。
例如:「商店」表中,有三個鍵屬性:name(商店名稱),type(商品供應類型),location(所在地區),滿足 BCNF 範式,假設每個商店在任意地區都提供同等數量的供應類型,那麼 name(不是超鍵)存在非平凡多值依賴:
name →→ type
name →→ location
即同一個商店,存在 type 與 location 的冗餘。不滿足 4NF。
總結
更多的範式這裡就不討論了,需要注意的是,範式並不是需要絕對遵守的準則,如果你的系統足夠簡單,例如僅僅需要展示用戶的聯繫方式,那麼將「聯繫方式」欄位設計為「手機+居住地址」並無不妥,只是遵守範式設計,會利於你的系統規模擴大,更加容易擴展,不會陷入性能低下、難以開發和維護的困境。
參考鏈接:
資料庫規範化
1NF:
Domain of each attribute is an elementary type; that is,
not a set or a record structure.
2NF:
Whenever X → A is a functional dependency that holds in
relation R and A ?∈ X , then either
? X is not a proper subset of any key for R.
3NF:
Whenever X → A is a functional dependency that holds in relation R and A ?∈ X , then either
? A is prime, or
? X is a key or a super-key for R.
BCNF:
Whenever X → A is a functional dependency that holds in
relation R and A ?∈ X , then
? X is a key or a super-key for R.
* An attribute A is called prime if A is in any of the candidate keys.
範式:英文名稱是 Normal Form,它是英國人 E.F.Codd(關係資料庫的老祖宗)在上個世紀70年代提出關係資料庫模型後總結出來的,範式是關係資料庫理論的基礎,也是我們在設計資料庫結構過程中所要遵循的規則和指導方法。目前有跡可尋的共有8種範式,依次是:1NF,2NF,3NF,BCNF,4NF,5NF,DKNF,6NF。通常所用到的只是前三個範式,即:第一範式(1NF),第二範式(2NF),第三範式(3NF)。下面就簡單介紹下這三個範式。
◆ 第一範式(1NF):強調的是列的原子性,即列不能夠再分成其他幾列。
考慮這樣一個表:【聯繫人】(姓名,性別,電話)
如果在實際場景中,一個聯繫人有家庭電話和公司電話,那麼這種表結構設計就沒有達到 1NF。要符合 1NF 我們只需把列(電話)拆分,即:【聯繫人】(姓名,性別,家庭電話,公司電話)。1NF 很好辨別,但是 2NF 和 3NF 就容易搞混淆。
◆ 第二範式(2NF):首先是 1NF,另外包含兩部分內容,一是表必須有一個主鍵;二是沒有包含在主鍵中的列必須完全依賴於主鍵,而不能只依賴於主鍵的一部分。
考慮一個訂單明細表:【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName)。
因為我們知道在一個訂單中可以訂購多種產品,所以單單一個 OrderID 是不足以成為主鍵的,主鍵應該是(OrderID,ProductID)。顯而易見 Discount(折扣),Quantity(數量)完全依賴(取決)於主鍵(OderID,ProductID),而 UnitPrice,ProductName 只依賴於 ProductID。所以 OrderDetail 表不符合 2NF。不符合 2NF 的設計容易產生冗餘數據。
可以把【OrderDetail】表拆分為【OrderDetail】(OrderID,ProductID,Discount,Quantity)和【Product】(ProductID,UnitPrice,ProductName)來消除原訂單表中UnitPrice,ProductName多次重複的情況。
◆ 第三範式(3NF):首先是 2NF,另外非主鍵列必須直接依賴於主鍵,不能存在傳遞依賴。即不能存在:非主鍵列 A 依賴於非主鍵列 B,非主鍵列 B 依賴於主鍵的情況。
考慮一個訂單表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主鍵是(OrderID)。
其中 OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity 等非主鍵列都完全依賴於主鍵(OrderID),所以符合 2NF。不過問題是 CustomerName,CustomerAddr,CustomerCity 直接依賴的是 CustomerID(非主鍵列),而不是直接依賴於主鍵,它是通過傳遞才依賴於主鍵,所以不符合 3NF。
通過拆分【Order】為【Order】(OrderID,OrderDate,CustomerID)和【Customer】(CustomerID,CustomerName,CustomerAddr,CustomerCity)從而達到 3NF。
第二範式(2NF)和第三範式(3NF)的概念很容易混淆,區分它們的關鍵點在於,2NF:非主鍵列是否完全依賴於主鍵,還是依賴於主鍵的一部分;3NF:非主鍵列是直接依賴於主鍵,還是直接依賴於非主鍵列。
資料庫三大範式的一己之見 - 予懷之言 - 博客頻道 - CSDN.NET
個人所見
回想來,我們日常開發都是跟著感覺來,不過基本也能滿足3NF,可能這個就是經驗吧。範式類的東西就是將經驗抽取成語言,不過真的在學習的時候,永遠不知道他的重要性
話說回來,好像有時候實際開發中,喜歡用,隔開把一些內容存放在一列中,這個貌似不滿足1NF那。。。我想說的是,這個問題下的答案,全都是大堆專業術語的堆疊,完全違背了費曼技巧——用掃地阿姨都能聽懂的比喻,來向他人形容任何一門深奧理論——的基本原則。
這條原則基本上也是快速學習所有複雜艱深的抽象理論的基礎。
所以,以下我給出讓人一看就懂的答案。
首先,所謂的資料庫,你可以理解為無數張excel表加在一起。
1.第一範式:
比如【性別】這個列名,絕大多數情況下無法再分;但是【所在地】這個列名,很多時候是可以根據你的需求往下分的,那麼它在某些情況下就不符合第一範式。
即所有表格的每一個列名都不可再分,同時與其它列名不重複。
2.第二範式:
比如我們為了評價一批蘋果的好壞,給蘋果上了編號1——10000。那麼這個【編號】就是我們要描述的對象,其餘的【顏色】、【香味】等列名,全部都是用來描述蘋果的。
同時,隨著主鍵值的變化,其它列名也必須隨之而變化。而因為主鍵可以是幾個列名的組合,比如以【食品種類】+【編號】作為一個主鍵,那麼在這種情況下,其它列名(副鍵)必須同時被這兩個列名影響,少一個的話,不行。
即一張表格只描述一個對象(主鍵),其它列名(副鍵)與對象之間相互完全依賴。
3.第三範式:
比如,你想要做【編號】、【顏色】、【香味】、【香味得分】、【香味評級】這種列名,那麼你要另開一張專門描述香味的表格。
再比如,你想要做【學號】、【姓名】、【性別】、【班級】、【班主任】這種列名,由於【班主任】受【班級】影響,那麼你要另開一張專門描述班級的表格。
即,副鍵與副鍵之間,不能存在依賴關係。
以上。
以我的淺薄見解.從面向對象角度來說的話(把一個元組看成一個對象)
第一範式:對象中任意一個Field不可分成多個Field
第二範式:對象中的成員變數存儲的內容,必須屬於這個對象(不能放別的對象的內容)
第三範式:對象中不能存放其他對象的引用(可以通過存放其他對象的ID之類的方式索引到其他對象)
很多年了,建表的時候能下意識感知哪裡不對,但一二三範式的概念總是記不熟,面試小朋友的時候這些概念都還要預熱下。總結了下,我自己要反過來記。
- 反1NF:把該放2個欄位的屬性擠到1個欄位里了。
String phoneNumber = "手機號:座機號";
String shouji = phoneNumber.split(":")[0];
String zuoji = phoneNumber.split(":")[1];
- 反2NF:把該放2個表的屬性擠到1張表裡了。
Person person = new Person(new Human(), new Job());
- 反3NF(用java里的引用和對象來理解):1個引用(存對象地址)就能拿到的東西,拖家帶口把本應分配到堆里對象的屬性都存棧上了。
//jvm中逃逸分析優化中的棧上分配時,把類的實例分配在棧上提高性能,跟我們實際工作中建表時違反3NF加一些冗餘欄位是一樣的道理。
1NF要求屬性不可再拆分,最原子級;
2NF包含1,並要求有主鍵;
3NF包含2,且消除冗餘數據;
第一範式:我把它理解為:表中不能有子表。
第三範式的話:有一種簡單的判斷方法:就是在依賴關係中A——&>B 這裡,A是候選碼或者B是主屬性。只要滿足這個關係就是第三範式。
推薦閱讀: