1. 程式人生 > >資料庫正規化:1NF、2NF、3NF、BCNF

資料庫正規化:1NF、2NF、3NF、BCNF

首先要明白”正規化(NF)”是什麼意思。按照教材中的定義,正規化是“符合某一種級別的關係模式的集合,表示一個關係內部各屬性之間的聯絡的合理化程度”。很晦澀吧?實際上你可以把它粗略地理解為一張資料表的表結構所符合的某種設計標準的級別。就像家裡裝修買建材,最環保的是E0級,其次是E1級,還有E2級等等。資料庫正規化也分為1NF,2NF,3NF,BCNF,4NF,5NF。一般在我們設計關係型資料庫的時候,最多考慮到BCNF就夠。符合高一級正規化的設計,必定符合低一級正規化,例如符合2NF的關係模式,必定符合1NF。

1NF的定義為:符合1NF的關係中的每個屬性都不可再分。
1NF是所有關係型資料庫的最基本要求,你在關係型資料庫管理系統(RDBMS),例如SQL Server,Oracle,MySQL中建立資料表的時候,如果資料表的設計不符合這個最基本的要求,那麼操作一定是不能成功的。也就是說,只要在RDBMS中已經存在的資料表,一定是符合1NF的。
但是僅僅符合1NF的設計,仍然會存在資料冗餘過大,插入異常,刪除異常,修改異常的問題

正因為僅符合1NF的資料庫設計存在著這樣那樣的問題,我們需要提高設計標準,去掉導致上述四種問題的因素,使其符合更高一級的正規化(2NF),這就是所謂的“規範化”。

第二正規化(2NF)在關係理論中的嚴格定義我這裡就不多介紹了(因為涉及到的鋪墊比較多),只需要瞭解2NF對1NF進行了哪些改進即可。其改進是,2NF在1NF的基礎之上,消除了非主屬性對於碼的部分函式依賴。接下來對這句話中涉及到的四個概念——“函式依賴”、“碼”、“非主屬性”、與“部分函式依賴”進行一下解釋。

函式依賴:
若在一張表中,在屬性(或屬性組)X的值確定的情況下,必定能確定屬性Y的值,那麼就可以說Y函式依賴於X,寫作 X → Y。我們可以說姓名函式依賴於學號,寫作 學號 → 姓名。但是反過來,因為可能出現同名的學生,所以有可能不同的兩條學生記錄,它們在姓名上的值相同,但對應的學號不同,所以我們不能說學號函式依賴於姓名
完全函式依賴:
在一張表中,若 X → Y,且對於 X 的任何一個真子集(假如屬性組 X 包含超過一個屬性的話),X ’ → Y 不成立,那麼我們稱 Y 對於 X 完全函式依賴,
部分函式依賴:
假如 Y 函式依賴於 X,但同時 Y 並不完全函式依賴於 X,那麼我們就稱 Y 部分函式依賴於 X

傳遞函式依賴:
假如 Z 函式依賴於 Y,且 Y 函式依賴於 X (嚴格來說還有一個X 不包含於Y,且 Y 不函式依賴於Z的前提條件),那麼我們就稱 Z 傳遞函式依賴於 X ,

碼:
設 K 為某表中的一個屬性或屬性組,若除 K 之外的所有屬性都完全函式依賴於 K(這個“完全”不要漏了),那麼我們稱 K 為候選碼,簡稱為碼。在實際中我們通常可以理解為:假如當 K 確定的情況下,該表除 K 之外的所有屬性的值也就隨之確定,那麼 K 就是碼。一張表中可以有超過一個碼。(實際應用中為了方便,通常選擇其中的一個碼作為主碼)

主屬性:
包含在任何一個碼中的屬性成為主屬性。

根據2NF的定義,判斷的依據實際上就是看資料表中是否存在非主屬性對於碼的部分函式依賴。若存在,則資料表最高只符合1NF的要求,若不存在,則符合2NF的要求


判斷的方法是:
第一步:找出資料表中所有的碼。
第二步:根據第一步所得到的碼,找出所有的主屬性。
第三步:資料表中,除去所有的主屬性,剩下的就都是非主屬性了。
第四步:檢視是否存在非主屬性對碼的部分函式依賴。
對於第一步,我們可以這麼做:
檢視所有每一單個屬性,當它的值確定了,是否剩下的所有屬性值都能確定。
檢視所有包含有兩個屬性的屬性組,當它的值確定了,是否剩下的所有屬性值都能確定。
檢視所有包含了三個屬性,也就是所有屬性的屬性組,當它的值確定了,是否剩下的所有屬性值都能確定。
……
看起來很麻煩是吧,但是這裡有一個訣竅,就是假如A是碼,那麼所有包含了A的屬性組,如(A,B)、(A,C)、(A,B,C)等等,都不是碼了(因為作為碼的要求裡有一個“完全函式依賴”)。

為了讓表3符合2NF的要求,我們必須消除這些部分函式依賴,只有一個辦法,就是將大資料表拆分成兩個或者更多個更小的資料表,在拆分的過程中,要達到更高一級正規化的要求,這個過程叫做”模式分解“。模式分解的方法不是唯一的(若碼只有一個屬性,則不可能存在非主屬性對於碼 的部分函式依賴,符合2NF的要求)

第三正規化(3NF):
僅僅符合2NF的要求,很多情況下還是不夠的,而出現問題的原因,在於仍然存在非主屬性對於碼的傳遞函式依賴。為了能進一步解決這些問題,我們還需要將符合2NF要求的資料表改進為符合3NF的要求。

3NF在2NF的基礎之上,消除了非主屬性對於碼的傳遞函式依賴。也就是說, 如果存在非主屬性對於碼的傳遞函式依賴,則不符合3NF的要求。

對於學生表,主碼為學號,主屬性為學號,非主屬性為姓名、系名和系主任。因為 學號 → 系名,同時 系名 → 系主任,所以存在非主屬性系主任對於碼學號的傳遞函式依賴,所以學生表的設計,不符合3NF的要求。。為了讓資料表設計達到3NF,我們必須進一步進行模式分解為以下形式:選課(學號,課名,分數)學生(學號,姓名,系名)系(系名,系主任)

由此可見,符合3NF要求的資料庫設計,基本上解決了資料冗餘過大,插入異常,修改異常,刪除異常的問題。當然,在實際中,往往為了效能上或者應對擴充套件的需要,經常 做到2NF或者1NF,但是作為資料庫設計人員,至少應該知道,3NF的要求是怎樣的。

BCNF正規化:
在某些特殊情況下,即使關係模式符合 3NF 的要求,仍然存在著插入異常,修改異常與刪除異常的問題,仍然不是 ”好“ 的設計。造成此問題的原因:存在著主屬性對於碼的部分函式依賴與傳遞函式依賴。(在此例中就是存在主屬性【倉庫名】對於碼【(管理員,物品名)】的部分函式依賴。解決辦法就是要在 3NF 的基礎上消除主屬性對於碼的部分與傳遞函式依賴。

下面各用一句話簡潔地描述:
1NF
定義:所有的屬性均有原子性
2NF(在滿足1NF的前提上)
定義:如果依賴於主鍵,則需要依賴於所有主鍵,不能存在依賴部分主鍵的情況
3NF:滿足2NF,非主鍵外的所有欄位必須互不依賴,非鍵屬性不能依賴於非鍵屬性。
BCNF:所有屬性(包括非鍵屬性與鍵鼠性)不能依賴於非鍵屬性。