理論性的東西,往往容易把人人都看得懂的東西寫成連鬼都看不懂,近似于主任醫(yī)生開的藥方。從前學(xué)范式的時候,把書中得概念翻來覆去看,看得痛心疾首深惡痛絕,再加上老師深切誤導(dǎo),最后一塌糊涂。借助網(wǎng)絡(luò)資源,自己寫了一篇,自己是看懂了,希望對大家也有所幫助,有錯誤幫忙指正。
數(shù)據(jù)庫范式(Normal forms):是用于規(guī)范關(guān)系型數(shù)據(jù)庫設(shè)計,以減少謬誤發(fā)生的一種準(zhǔn)則。
1NF(first normal form):
Table faithfully represents a relation and has no repeating groups.
數(shù)據(jù)庫表必須如實地展現(xiàn)“關(guān)系”,并且不允許有“重復(fù)組”出現(xiàn)。
這樣的概念真是令人痛心疾首,我們只好再搬出1NF的的作者之一Chris Date的解釋:
1. There's no top-to-bottom ordering to the rows.
(任意兩行沒有特定的順序關(guān)系。不存在一個特定的理由要某一行必須在另一行之前。)
2. There's no left-to-right ordering to the columns.
(任意兩列沒有特定的順序關(guān)系。)
3. There are no duplicate rows.
(不允許存在重復(fù)的行。如果一張表沒有Unique Key,事實上它是違反1NF的。)
4. Every row-and-column intersection contains exactly one value from the applicable domain (and nothing else).
(不允許出現(xiàn)空值Null,這一點不同作者是有爭議的。事實上我們常常違背這點。)
5. All columns are regular [i.e. rows have no hidden components such as row IDs, object IDs, or hidden timestamps].
(不允許存在隱藏字段。不知道Oracle的Rowid屬不屬于這個?)
有人從第四點的“one value”大肆挖掘,于是我們就見到了書上這樣的定義:“如果一個關(guān)系模式R的所有屬性都是原子的,即不可再分的基本數(shù)據(jù)項,則RÎ1NF”。
這一點被認(rèn)為是1NF的核心,“關(guān)系模式R”↔“表”,“屬性” ↔ “列”,下面是一種與1NF不一致的情況,通常這是一類很明顯的設(shè)計缺陷:
ID
|
Artist
|
FavoriteColor
|
……
|
1
|
Babyface
|
Blue,Yellow
|
……
|
2
|
Sting
|
Green
|
……
|
對上例我們不能把它拆分成FavoriteColor1、FavoriteColor2……因為首先我們不能確定該拆分成幾列;其次FavoriteColor1與FavoriteColor2在結(jié)構(gòu)、含意方面都是相同的,這實際上也是一類“repeating group”;同時這種設(shè)計會導(dǎo)致某些查詢困難,比如“有哪些藝人喜歡黃色?”
解決方案是將表拆分成兩個:
ID
|
Artist
|
……
|
1
|
Babyface
|
……
|
2
|
Sting
|
……
|
ID
|
FavoriteColor
|
1
|
Blue
|
1
|
Yellow
|
2
|
Green
|
總結(jié):
對1NF最核心的 “原子性”,違反此規(guī)范的可能性:接近于0%。不過,網(wǎng)上很多帖子說在關(guān)系型數(shù)據(jù)庫中根本不可能違背1NF,我認(rèn)為這是不對的。
2NF(second normal form):
No non-prime attribute in the table is functionally dependent on a part (proper subset) of a candidate key.
不存在非主屬性對任一候選鍵的部分函數(shù)依賴。
如果解釋完下面幾個概念,這個定義就可以讀懂了:
Superkey:超級鍵(L),如果屬性或?qū)傩越M合能唯一標(biāo)識一條記錄,則它是一個Superkey。
Candidate key:候選鍵,當(dāng)Superkey只包含一個屬性時,則它是一個候選鍵;當(dāng)Superkey包含一組屬性時,僅當(dāng)這一組屬性不包含另一Superkey時,它是一個候選鍵。換句話說,候選鍵是“純凈的”、最小化的Superkey。
Non-prime attribute:非主屬性,未在任何候選鍵中出現(xiàn)的屬性,即為非主屬性。
舉例來說,對表{First_name,Last_name,Address},假定全名不重復(fù),則:
Superkey:
{First_name,Last_name}
{First_name,Last_name,Address}
Candidate key:
{First_name,Last_name}
Non-prime attribute:
Address
淺白版:“2NF針對的是復(fù)合候選鍵(即鍵包含的字段個數(shù)>1)的情況,非主屬性不能只依賴于復(fù)合候選鍵中的一部分字段。”顯然,如果是非復(fù)合候選鍵,如果它符合1NF,那么它一定符合2NF。
假設(shè)有這樣一張涉及藝人與唱片公司的關(guān)系表:
Artist
藝人
|
Company
唱片公司
|
DurationYears
簽約總年數(shù)
|
CompAddr
公司住址
|
Babyface
|
Solar
|
4
|
Indiana
|
Babyface
|
Laface
|
2
|
Indiana
|
|
|
|
|
顯然,{Artist,Company}為可以作為一個候選鍵,DurationYears在這沒有問題,但CompAddr是違反2NF的,它只依賴于候選鍵的一部分(依賴于Company),這是違反2NF的,為了消除這種情況,我們可以:
Artist
藝人
|
CompID
唱片公司
|
DurationYears
簽約總年數(shù)
|
Babyface
|
1
|
4
|
Babyface
|
2
|
2
|
ID
|
Company
唱片公司
|
CompAddr
公司住址
|
1
|
Solar
|
Indiana
|
2
|
Laface
|
Indiana
|
總結(jié):
對于2NF,如果關(guān)系中的候選鍵只包含一個屬性,可以直接略過。
在考慮2NF的過程中,不要把幾個無關(guān)的實體的屬性雜揉放在一個關(guān)系中,比如Artist是一個實體、Company是一個實體,它們可以有一系列的關(guān)聯(lián)表(也是實體),但在關(guān)聯(lián)表中盡量不要引入前兩個實體的無關(guān)屬性。
3NF(Third normal form)
Every non-prime attribute is non-transitively dependent on every key of the table.
不存在非主屬性對任一鍵(候選鍵)的傳遞依賴。
傳遞依賴,你可以顧名思義,這里就不再引入定義了,舉個例子,有下面一張表:
Tournament
賽事
|
Year
年份
|
Winner
冠軍
|
Winner Date of Birth
冠軍生日
|
Indiana Invitational
|
1998
|
Al Fredrickson
|
21 July 1975
|
Cleveland Open
|
1999
|
Bob Albertson
|
28 September 1968
|
Des Moines Masters
|
1999
|
Al Fredrickson
|
21 July 1975
|
Indiana Invitational
|
1999
|
Chip Masterson
|
14 March 1977
|
這里的候選鍵為{Tournament,Year},顯然有這樣的決定關(guān)系:
{Tournament,Year}→Winner
{Tournament,Year}→Winner→Winner Date of Birth
其中第二條就屬于違反3NF的情況,因為Winner Date of Birth依賴于Winner而不是直接依賴于候選鍵。這種情況下,可以將Winner,Winner Date of Birth單獨(dú)作為一張表,這里不贅述。
總結(jié):
我覺得大多數(shù)人憑借直觀感覺,就可使設(shè)計的關(guān)系符合3NF,所以這些理論,你只需要姑且讀之。
BCNF(Boyce-Codd normal form)(Boyce與Codd是該范式的兩名作者。)
Every non-trivial functional dependency in the table is a dependency on a superkey.
表中的任何非平凡函數(shù)依賴,都必須是對superkey的依賴。
non-trivial functional dependency:非平凡函數(shù)依賴,如果存在一個決定關(guān)系x→y,且y并非x的子集,則叫著y非平凡函數(shù)依賴于x。
BCNF與3NF的最大區(qū)別是它并不僅針對非主屬性(non-prime attribute)來說,它發(fā)生的時候常常是表中根本不存在非主屬性,以至于它不可能違反2NF或3NF。而BCNF的出現(xiàn)就是為了擴(kuò)大“打擊面”。
于是BCNF的主旨是:補(bǔ)充對發(fā)生在主屬性(prime attribute)身上的函數(shù)依賴的約束,因為對于非主屬性的約束已經(jīng)在3NF中完成了。
例子,使用關(guān)系表描述學(xué)生、課程、教師的關(guān)系(假定一名教師只負(fù)責(zé)一門課程,一門課程則可以由多位教師負(fù)責(zé)):
Student
學(xué)生
|
Course
課程
|
Teacher
教師
|
S1
|
C1
|
T1
|
S1
|
C2
|
T2
|
S2
|
C1
|
T1
|
S2
|
C2
|
T3
|
S2
|
C3
|
T2
|
候選鍵:
{Student,Course}
{Student,Teacher}
因此這里不存在非主屬性,而在主屬性的函數(shù)依賴中,存在Teacher→Course,這屬于違反BCNF的情況。
可是,問題是這個表看起來還挺正常的啊?!它的毛病在于,我們無法阻止類似最后一行這樣的數(shù)據(jù)插入,而這會導(dǎo)致與前提“一名教師只負(fù)責(zé)一門課程”違背。所以我們還是需要將它拆分:
Student
學(xué)生
|
Teacher
教師
|
S1
|
T1
|
S1
|
T2
|
S2
|
T1
|
S2
|
T3
|
Teacher
教師
|
Course
課程
|
T1
|
C1
|
T2
|
C2
|
T3
|
C2
|
這樣,在“Teacher-Course”表中,借助主鍵的幫助,最后可以避免違背“一名教師只負(fù)責(zé)一門課程”這個前提。
那么,如果沒有這樣一個前提,是初的設(shè)計是否符合BCNF?目前看來是的。
真實的情況可能更為復(fù)雜,下面這個更接近于我的一些經(jīng)歷:
1)學(xué)生需要學(xué)習(xí)多門課程
2)一門課程可能有多位教師負(fù)責(zé)
3)一位教師可能負(fù)責(zé)多門課程
4)某一班級的某一課程對應(yīng)的教師是固定的(一位)
據(jù)此,為了描述學(xué)生、課程、教師三者的關(guān)系,從這一團(tuán)亂麻中最早跳出來的大概是這樣的表:
Student
學(xué)生
|
Class
班級
|
Course
課程
|
Teacher
教師
|
|
|
|
|
|
|
|
|
候選鍵:
{Student,Course}
我們可以明顯地看到Student→Class違反了2NF,于是:
Class
班級
|
Course
課程
|
Teacher
教師
|
|
|
|
|
|
|
從這兩張表,仔細(xì)考慮,即便我們通過Class關(guān)聯(lián)兩張表,還是無法得出學(xué)生與課程的關(guān)系(只能得出可供該學(xué)生選擇的課程),所以我們需要再添加一張表:
Student
學(xué)生
|
Course
課程
|
|
|
|
|
最后大概是這么三張表,可能還有其它的方案,這里只是舉例說明,就不糾纏了。
在BCNF之后,還有4NF,5NF,DKNF,6NF,等什么時候有空了再看看是什么東東。