1. 程式人生 > >資料庫正規化1NF 2NF 3NF BCNF(例項)通俗易懂的講解

資料庫正規化1NF 2NF 3NF BCNF(例項)通俗易懂的講解

正規化應用

    我們來逐步搞定一個論壇的資料庫,有如下資訊:
    (1) 使用者:使用者名稱,email,主頁,電話,聯絡地址
    (2) 帖子:發帖標題,發帖內容,回覆標題,回覆內容

    第一次我們將資料庫設計為僅僅存在表:
    使用者名稱 email 主頁 電話 聯絡地址 發帖標題 發帖內容 回覆標題 回覆內容
    這個資料庫表符合第一正規化,但是沒有任何一組候選關鍵字能決定資料庫表的整行,唯一的關鍵欄位使用者名稱也不能完全決定整個元組。我們需要增加"發帖ID"、"回覆ID"欄位,即將表修改為:
    使用者名稱 email 主頁 電話 聯絡地址 發帖ID 發帖標題 發帖內容 回覆ID 回覆標題 回覆內容 
    這樣資料表中的關鍵字(使用者名稱,發帖ID,回覆ID)能決定整行:
    (使用者名稱,發帖ID,回覆ID) → (email,主頁,電話,聯絡地址,發帖標題,發帖內容,回覆標題,回覆內容)
    但是,這樣的設計不符合第二正規化,因為存在如下決定關係:
    (使用者名稱) → (email,主頁,電話,聯絡地址)
    (發帖ID) → (發帖標題,發帖內容)
    (回覆ID) → (回覆標題,回覆內容)
    即非關鍵欄位部分函式依賴於候選關鍵欄位,很明顯,這個設計會導致大量的資料冗餘和操作異常。

我們將資料庫表分解為(帶下劃線的為關鍵字):
(1) 使用者資訊:使用者名稱,email,主頁,電話,聯絡地址
(2) 帖子資訊:發帖ID,標題,內容
(3) 回覆資訊:回覆ID,標題,內容
(4) 發貼:使用者名稱,發帖ID
(5) 回覆:發帖ID,回覆ID

    這樣的設計是滿足第1、2、3正規化和BCNF正規化要求的,但是這樣的設計是不是最好的呢?
不一定。

    觀察可知,第4項"發帖"中的"使用者名稱"和"發帖ID"之間是1:N的關係,因此我們可以把"發帖"合併到第2項的"帖子資訊"中;第5項"回覆"中的"發帖ID"和"回覆ID"之間也是1:N的關係,因此我們可以把"回覆"合併到第3項的"回覆資訊"中。這樣可以一定量地減少資料冗餘,新的設計為:
(1) 使用者資訊:使用者名稱,email,主頁,電話,聯絡地址
(2) 帖子資訊:使用者名稱,發帖ID,標題,內容
(3) 回覆資訊:發帖ID,回覆ID,標題,內容

    資料庫表1顯然滿足所有正規化的要求;

    資料庫表2中存在非關鍵字“標題”、“內容”對關鍵欄位“發帖ID”的部分函式依賴,即不滿足第二正規化的要求,但是這一設計並不會導致資料冗餘和操作異常;

    資料庫表3中也存在非關鍵欄位"標題"、"內容"對關鍵欄位"回覆ID"的部分函式依賴,也不滿足第二正規化的要求,但是與資料庫表2相似,這一設計也不會導致資料冗餘和操作異常。

    由此可以看出,並不一定要強行滿足正規化的要求,對於1:N關係,當1的一邊合併到N的那邊後,N的那邊就不再滿足第二正規化了,但是這種設計反而比較好!

    對於M:N的關係,不能將M一邊或N一邊合併到另一邊去,這樣會導致不符合正規化要求,同時導致操作異常和資料冗餘。

    對於1:1的關係,我們可以將左邊的1或者右邊的1合併到另一邊去,設計導致不符合正規化要求,但是並不會導致操作異常和資料冗餘。