1. 程式人生 > >資料庫的正規化:第一正規化、第二正規化、第三正規化、BC正規化、第四正規化

資料庫的正規化:第一正規化、第二正規化、第三正規化、BC正規化、第四正規化

簡介

資料庫正規化在資料庫設計中的地位一直很曖昧,教科書中對於資料庫正規化倒是都給出了學術性的定義,但實際應用中正規化的應用卻不甚樂觀,這篇文章會用簡單的語言和一個簡單的資料庫DEMO將一個不符合正規化的資料庫一步步從第一正規化實現到第四正規化。

關鍵碼
1) 超鍵:在關係中能唯一標識元組的屬性或屬性集稱為關鍵模式的超鍵。
2)候選鍵:不含有多餘屬性的超鍵稱為候選鍵。也就是在候選鍵中在刪除屬性就不是鍵了。
3) 主鍵:使用者選作元組標識的候選鍵稱為主鍵。一般不加說明,鍵就是指主鍵。
4) 外來鍵:如果模式R中屬性K是其他模式的主鍵,那麼K在模式R中稱為外來鍵。

完全依賴、部分依賴、傳遞依賴


部分函式依賴:設X,Y是關係R的兩個屬性集合,存在X→Y,若X’是X的真子集,存在X’→Y,則稱Y部分函式依賴於X。
舉個例子:學生基本資訊表R中(學號,身份證號,姓名)當然學號屬性取值是唯一的,在R關係中,(學號,身份證號)->(姓名),(學號)->(姓名),(身份證號)->(姓名);所以姓名部分函式依賴與(學號,身份證號);

完全函式依賴:設X,Y是關係R的兩個屬性集合,X’是X的真子集,存在X→Y,但對每一個X’都有X’!→Y,則稱Y完全函式依賴於X。
例子:學生基本資訊表R(學號,班級,姓名)假設不同的班級學號有相同的,班級內學號不能相同,在R關係中,(學號,班級)->(姓名),但是(學號)->(姓名)不成立,(班級)->(姓名)不成立,所以姓名完全函式依賴與(學號,班級);

傳遞函式依賴:設X,Y,Z是關係R中互不相同的屬性集合,存在X→Y(Y !→X),Y→Z,則稱Z傳遞函式依賴於X。
例子:在關係R(學號 ,宿舍, 費用)中,(學號)->(宿舍),宿舍!=學號,(宿舍)->(費用),費用!=宿舍,所以符合傳遞函式的要求;

正規化的目標

應用資料庫正規化可以帶來許多好處,但是最重要的好處歸結為三點:

1.減少資料冗餘(這是最主要的好處,其他好處都是由此而附帶的)
2.消除異常(插入異常,更新異常,刪除異常)
3.讓資料組織的更加和諧…

但劍是雙刃的,應用資料庫正規化同樣也會帶來弊端,這會在文章後面說到。

什麼是正規化

簡單的說,正規化是為了消除重複資料減少冗餘資料,從而讓資料庫內的資料更好的組織,讓磁碟空間得到更有效利用的一種標準化標準,滿足高等級的正規化的先決條件是滿足低等級正規化。(比如滿足2nf一定滿足1nf),

DEMO
讓我們先從一個未經正規化化的表看起,表如下:
nonf
先對錶做一個簡單說明,employeeId是員工id,departmentName 是部門名稱,job代表崗位,jobDescription是崗位說明,skill是員工技能,
departmentDescription是部門說明,address是員工住址。

對錶進行第一正規化(1NF)

如果一個關係模式R的所有屬性都是不可分的基本資料項,則R∈1NF。

簡單的說,第一正規化就是每一個屬性都不可再分。不符合第一正規化則不能稱為關係資料庫。對於上表,不難看出Address是可以再分的,比如”北京市XX路XX小區XX號”,著顯然不符合第一正規化,對其應用第一正規化則需要將此屬性分解到另一個表,如下:
1nf
對錶進行第二正規化(2NF)

若關係模式R∈1NF,並且每一個非主屬性都完全函式依賴於R的碼,則R∈2NF。

簡單的說,是表中的屬性必須完全依賴於全部主鍵,而不是部分主鍵。所以只有一個主鍵的表如果符合第一正規化,那一定是第二正規化。這樣做的目的是進一步減少插入異常和更新異常。在上表中,departmentDescription是由主鍵DepartmentName所決定,但卻不是由主鍵EmployeeID決定,所以departmentDescription只依賴於兩個主鍵中的一個,故要departmentDescription對主鍵是部分依賴,對其應用第二正規化如下表:
2nf

對錶進行第三正規化(3NF)

關係模式R中若不存在這樣的碼X、屬性組Y及非主屬性Z(Z∈ Y), 使得X→Y,Y→Z,成立,則稱R∈ 3NF。

簡單的說,第三正規化是為了消除資料庫中關鍵字之間的依賴關係,在上面經過第二正規化化的表中,可以看出jobDescription(崗位職責)是由job(崗位)所決定,則jobDescription依賴於job,可以看出這不符合第三正規化,對錶進行第三正規化後的關係圖為:

3nf
上表中,已經不存在資料庫屬性互相依賴的問題,所以符合第三正規化。

對錶進行BC正規化(BCNF)
設關係模式R∈1NF,如果對於R的每個函式依賴X→Y,若Y不屬於X,則X必含有候選碼,那麼R∈BCNF。

簡單的說,bc正規化是在第三正規化的基礎上的一種特殊情況,既每個表中只有一個候選鍵(在一個數據庫中每行的值都不相同,則可稱為候選鍵),在上面第三正規化的noNf表中可以看出,每一個員工的email都是唯一的(難道兩個人用同一個email??)則,此表不符合bc正規化,對其進行bc正規化化後的關係圖為:
bcnf
對錶進行第四正規化(4NF)

關係模式R∈1NF,如果對於R的每個非平凡多值依賴X→Y(Y∈X),X都含有候選碼,則R∈4NF。

簡單的說,第四正規化是消除表中的多值依賴,也就是說可以減少維護資料一致性的工作。對於上面bc正規化化的表中,對於員工的skill,兩個可能的值是”C#,sql,javascript”和“C#,UML,Ruby”,可以看出,這個資料庫屬性存在多個值,這就可能造成資料庫內容不一致的問題,比如第一個值寫的是”C#”,而第二個值寫的是”C#.net”,解決辦法是將多值屬性放入一個新表,則第四正規化化後的關係圖如下:
4nf1
而對於skill表則可能的值為:
4nf2
總結

上面對於資料庫正規化進行分解的過程中不難看出,應用的正規化登記越高,則表越多。表多會帶來很多問題:
1、查詢時要連線多個表,增加了查詢的複雜度;
2、查詢時需要連線多個表,降低了資料庫查詢效能。
而現在的情況,磁碟空間成本基本可以忽略不計,所以資料冗餘所造成的問題也並不是應用資料庫正規化的理由。
因此,並不是應用的正規化越高越好,要看實際情況而定。第三正規化已經很大程度上減少了資料冗餘,並且減少了造成插入異常,更新異常,和刪除異常了。我個人觀點認為,大多數情況應用到第三正規化已經足夠,在一定情況下第二正規化也是可以的。