資料庫正規化

2013-03-19_091950

這是MySQL 5實力養成暨評量裡的1-32.『可以消除表格部份依賴關係的是下列哪個正規化?

答案:(B) 第二正規化

已經上過資料庫的課很多次了,可是關於資料庫正規化的問題還是無法解決真是愚蠢。所以我們參考維基的說明再好好看一遍吧。

資料庫 正規化

資料庫正規化,又稱資料庫或資料庫正規化、標準化,是資料庫設計中的一系列原理和技術,以減少資料庫中資料冗餘,增進資料的一致性。關聯模型的發明者埃德加·科德最早提出這一概念,並於1970年代初定義了第一正規化、第二正規化和第三正規化的概念,還與Raymond F. Boyce於1974年共同定義了第三正規化的改進範式——BC正規化。
除外還包括針對多值依賴的第四正規化,連線依賴的第五正規化,DK正規化和第六正規化。
現在資料庫設計最多滿足3NF,普遍認為範式過高,雖然具有對資料關聯更好的約束性,但也導致資料關聯表增加而令資料庫IO更易繁忙,原來交由資料庫處理的關聯約束現更多在資料庫使用程式中完成。

第一正規化

第一正規化(1NF,中國大陸譯作第一範式)是資料庫正規化中所使用的一種正規形式。第一正規化是為了要排除重複群的出現,所採用的方法是要求資料庫的每個欄位都只能存放單一值,而且每筆記錄都要能利用一個唯一的主鍵來加以識別。

不符合第一正規化的情況

重複群

重複群通常會出現在會計帳上,每一筆記錄可能有不定個數的值。舉例來說:

交易
顧客 日期 數量
Pete Monday 19.00-28.20
Pete Wednesday -84.00
Sarah Friday 100.00150.00-40.00

‘數量’ 就是所謂的重複群了,而在這種情況下這份資料就不符合第一正規化。想要消除重複群的話,只要把每筆記錄都轉化為單一記錄即可:

交易
交易 ID 顧客 日期 數量
1 Pete Monday 19.00
2 Pete Monday -28.20
3 Pete Wednesday -84.00
4 Sarah Friday 100.00
5 Sarah Friday 150.00
6 Sarah Friday -40.00

缺乏唯一識別碼

一樣是在交易這個例子中,同一天同一個人買了同樣的數量,這樣的交易做了兩次:

交易
顧客 日期 數量
Pete Monday 19.00
Pete Monday 19.00

如上所示,這兩筆交易可以說是一模一樣,也就是說如果只靠這些資料我們沒有辦法分辨這兩筆記錄。我們之所以說它不符合第一正規化,是因為上面這樣的表示法欠缺一個唯一識別碼,可以是一個欄位,也可以是一組欄位,而且可以保證在這個資料中唯一識別碼不會重複出現。要將它正規化到符合第一正規化的原則只需要加入一個唯一識別碼即可:

交易
交易 ID 顧客 日期 數量
1 Pete Monday 19.00
2 Pete Monday 19.00

關聯式資料庫裡的第一正規化

[ads2]

大多數的 RDBMS (關聯式資料庫),像MySQL,允許使用者在定義資料表的時候不去指定主鍵,不過這麼一來這種資料表就不符合第一正規化了。

從某個角度看來,不允許重複群的出現是關聯式資料庫表示資訊的方法,RDBMS 裡資料表每一筆記錄的每一個欄位都只能有一個值。舉例來說,如果定義了一個叫做 Favorite Number 的整數欄位,每一筆記錄的 Favorite Number 這個欄位都只會是一個整數 (或是無);這也就是說,如果設定了主鍵的話,理論上不可能會有任何關聯式資料庫的資料表會違反第一正規化的原則。

不過就算是在這種情況下,還是可以設計出在骨子裡違反第一正規化的資料表。最簡單的方法就是把多個有意義的值編碼過後存進一個欄位裡,然後在資料表中用很多欄位來表達同一個事實。

單一欄位中有多個有意義的值

在單一欄位中存放多個值是違反第一正規化的做法,下面這個就是很好的例子,它把多個值用逗號分開來表示:

挑食列表
不喜歡的食物
Jim Liver, Goat’s cheese
Alice Broccoli
Norman Pheasant, Liver, Peas

以這樣的設計看來,想要知道有什麼人不喜歡某樣特定的東西是很不容易的。不過可以把這個資料表轉化成下面這種符合第一正規化的型式:

挑食列表
不喜歡的食物
Jim Liver
Jim Goat’s cheese
Alice Broccoli
Norman Pheasant
Norman Liver
Norman Peas

用很多欄位來表達同一個事實

在同一個資料表裡用多個欄位來表達同一個事情也是違反第一正規化的:

個人資料
喜歡的顏色 不喜歡的食物 (1) 不喜歡的食物 (2) 不喜歡的食物 (3)
Jim Green Liver Goat’s cheese
Alice Fuchsia Broccoli
Norman Blue Pheasant Liver Peas
Emily Yellow

就算我們能確定每個人不喜歡吃的食物最多不會超過三樣,這還是一個很糟的設計。舉例來說,我們想要知道所有不喜歡同一種食物的人的組合的話,這就不是件容易的事,因為食物有可能出現在任何一個欄位,也就是說每一次的查詢都要去檢查 9 (3 x 3) 組不同的欄位組合。

第二正規化

[ads2]

第二正規化(2NF,中國大陸譯作第二范式)是資料庫正規化中所使用的一種正規形式。它的規則是要求資料表裡的所有資料都要和該資料表的主鍵有完全相依關係;如果有哪些資料只和主鍵的一部份有關的話,就得把它們獨立出來變成另一個資料表。如果一個資料表的主鍵只有單一一個欄位的話,它就一定符合第二正規化。

一個資料表符合第二正規化若且唯若

  • 它符合第一正規化
  • 所有非主鍵的欄位都一定和主鍵有關

範例

有一個資料表記錄了設備元件的資訊,如下所示:

元件來源
元件 ID (主鍵) 供應商 ID (主鍵) 供應商名稱 價格 供應商住址
65 2 Stylized Parts 59.99 VA
73 2 Stylized Parts 20.00 VA
65 1 ACME Industries 69.99 CA

這個資料表的每個值都是單一值,所以它符合第一正規化。因為同一個元件有可能由不同的供應商提供,所以得把元件 ID 和供應商 ID 合在一起組成一個主鍵。

主鍵和價格之間的關係很正確:同一個元件在不同供應商有可能會有不同的報價,所以價格確實和主鍵完全相關(完全依賴)。

另一方面,供應商的名稱和住址就只和供應商 ID 有關(部分依賴),這不符合第二正規化的原則。仔細看就會發現 “Stylized Parts” 這個名稱和 “VA” 這個住址重複出現了兩次;要是它改名了或是被其他公司併購了怎麼辦?這時候最好把這些資料存到第二個資料表中:

供應商
供應商 ID (主鍵) 名稱 住址
1 ACME Industries CA
2 Stylized Parts VA

這麼一來,原本的 “元件來源” 資料表就得要做相對應的更動:

元件來源
元件 ID (主鍵) 供應商 ID (主鍵) 價格
65 2 59.99
73 2 20.00
65 1 69.99

檢查資料表裡的每個欄位,確認它們是不是都和主鍵完全相關,這樣才能知道這個資料表是不是符合第二正規化;如果不是的話,就把那些不完全相關的欄位移到獨立的資料表裡。接下來的步驟是要確保所有不是鍵的欄位都和彼此沒有相依關係,這就叫做第三正規化

第三正規化

第三正規化(3NF,中國大陸譯作第三范式)是資料庫正規化中所使用的一種正規形式,用來檢驗是否所有非鍵屬性都只和候選鍵有相關性,也就是說所有非鍵屬性互相之間應該是無關的。

第三正規化和第二正規化不同的地方在於,在第三正規化裡,所有的非鍵屬性都必須和每個候選鍵有直接相關。如果再對第三正規化做進一步加強就成了BC正規化,它所強調的重點就在於 “資料間的關係是奠基在鍵上、以整個鍵為考量、而且除了鍵之外不考慮其他因素”。

正規定義

  • {R} 表一個關係;
  • F 表維持 R 所需的一組功能相依性
  • X 表 R 屬性的子集合
  • A 表 R 的一個屬性

如果對於 X to A 這種型式的功能相依性而言,下列敘述任一為真的話,則可以稱 R 符合第三正規化:

任何一個具有部份相依性或是轉移相依性的關係都違反了第三正規化。

範例

[ads2]

以下面這個定義機械元件的關係為例:

機械元件
元件編號
(主鍵)
製造商名稱 製造商位址
1000 Toyota Park Avenue
1001 Mitsubishi Lincoln Street
1002 Toyota Park Avenue

本例中製造商位址很明顯地不該被列在這個關係裡面,因為和元件本身比起來,製造商位址應該和製造商比較有關係;正確的做法應該是把獨立成為一個新的資料表:

製造商
製造商名稱
(主鍵)
製造商位址
Toyota Park Avenue
Mitsubishi Lincoln Street

然後把原本的資料表改成這樣:

機械元件
元件編號
(主鍵)
製造商名稱
1000 Toyota
1001 Mitsubishi
1002 Toyota

先前那個資料表的問題在於每提到一次製造商名稱就要多存一次它的位址,而這就不符合第三正規化的原則。

下面提供了另一個例子:

訂單 (Order)
訂單編號 (Order Number)
(主鍵)
客戶名稱 (Customer Name) 單價 (Unit Price) 數量 (Quantity) 小計 (Total)
1000 David $35.00 3 $105.00
1001 Jim $25.00 2 $50.00
1002 Bob $25.00 3 $75.00

在本例中,非主鍵欄位完全依賴於主鍵訂單編號,也就是說唯一的訂單編號能導出唯一非主鍵欄位值,符合第二正規化。第三正規化要求非主鍵欄位之間不能有依賴關系,顯然本例中小計依賴於非主鍵欄位單價和數量,不符合第三正規化。小計不應該放在這個資料表裡面,只要把單價乘上數量就可以得到小計了;如果想要符合第三正規化的話,就把小計拿掉吧 (不過在做查詢的時候,本來用 “SELECT Orders.Total FROM Order” 就要改成用 “SELECT UnitPrice * Quantity FROM Order” 了)。

訂單 (Order)
訂單編號 (Order Number)
(主鍵)
客戶名稱 (Customer Name) 單價 (Unit Price) 數量 (Quantity)
1000 David $35.00 3
1001 Jim $25.00 2
1002 Bob $25.00 3

BC正規化

Boyce-Codd範式(Boyce-Codd normal form,BCNF),是資料庫正規化中所使用的一種正規形式。是在第三正規化的基礎上加上更嚴格約束,每個BCNF關聯是第三正規化的子集,有從屬關聯。它的定義是:

如果對於關聯模式R中存在的任意一個非平凡函式依賴X->A,都滿足X是R的一個候選鍵,那麼關聯模式R就屬於BCNF,。

BCNF與第三正規化的不同之處在於,第三正規化允許A是主屬性(第三正規化中不存在非主屬性被另一個非主屬性決定),而在BCNF中,任何屬性(包括非主屬性和主屬性)都不能被非主屬性所決定。

範例

關聯模式R:

Property_id#(主鍵) County_name Lot# Area

其中依賴關聯如下: Property_id#->{County_name,Lot#,Area}; {County_name,Lot#}->{Property_id#,Area}; Area->County_name; 很明顯最後一個依賴違反了BC正規化的要求,Area不是關聯模式R的主鍵,而依賴於它的County_name是能夠決定其他屬性的主屬性。故應當規範化為:

Property_id#(主鍵) County_name Lot#
Area(主鍵) County_name

資料庫正規化練習

1.您有一個包含下列資料的資料表

ProductName

Color1

Color2

Color3

Shirt

Blue

Green

Purple

您將該資料表切割為下列兩個資料表。

ProductID ProductName
4545 Shirt

 

ProductID Color
4545 Blue
4545 Green
4545 Purple

 

此程序稱為:

(A)重組

(B)反正規化

(C)分散

(D)正規化

資料庫正規化練習2,兆豐國際商業銀行 107 年第二次新進行員甄選試題,資料庫正規化,是資料庫設計中的一系列原理和技術,以減少資料庫中資料冗餘,增進資料的一致性。現在資料庫設計,普遍認為範式過高,雖然具有對資料關係更好的約束性,但也導致資料關係表增加而令資料庫 IO 更易繁忙,所以一般資料庫設計最多可滿足下列何者?
(a)第一正規化 (b)第二正規化 (c)第三正規化 (d)第四正規化

※2022/04/21 另一個正規化例子分享

資料表正規化(Normalization)之主要目的為何?
(a)修正資料錯誤 (b)清除不必要資料 (c)簡化屬性間關係 (d)減少資料不正常

※2022/06/02

新增一個資料庫正規化的讀書會Youtube

延伸閱讀-更多高CP值的部落格好文在這邊:

MySQL 流程控制的迴圈,用while寫mysql for loop
何謂資料隱碼(SQL injection)攻擊?程式設計師應如何預防?
MySQL 註解語法
C# List 定義及七種常用方法
用G Suite協作平台Google Sites打造專業的賺錢網站在家工作

感謝你看到這裡,很快就可以離開了,但最好的獎勵行動就是按一下幫我分享或留言,感恩喔~

點我分享到Facebook

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *