[原創] 基礎中的基礎(三):理解數據庫的幾種鍵和幾個範式

  在上學的時候,數據庫是一門讓我比較頭大的課程。記得當時教材上淨是一些晦澀難懂的語言,沒有充足的實例來幫助理解。前一陣子在看《網絡遊戲服務器端編程》的過程當中,忽然對數據庫範式有了一些感受,在此總結一下,分享給你們。做者純菜鳥,即便總結這些基礎知識也不免有錯,但願給位大牛不吝賜教,謝謝!html

  鍵(關係鍵)以及數據庫範式都是關係數據庫的概念。所謂關係鍵,指的是一個表中的一個(或一組)屬性,用來標識該表的每一行與另外一個表產生聯繫算法

  數據庫的」範式「,指的是設計數據庫的規則。按照必定的規則設計出數據庫的表和關係,可以避免在一些狀況下的查詢出錯,並具備良好的結構。總的來講,隨着範式等級的提升,數據表屬性之間的依賴關係愈來愈小,數據冗餘愈來愈低。但同時,數據關係變得更加複雜,訪問一個具體數據的關係層次增長。因此像設計模式同樣,不該盲目追求範式等級,應根據具體需求來選擇範式。數據庫

 

  咱們先來看一下幾種常見的數據庫關係鍵:編程

  一、超鍵(super key):可以惟一標識一條記錄的屬性或屬性集。設計模式

    • 標識性:一個數據表的全部記錄都具備不一樣的超鍵
    • 非空性:不能爲空

  二、候選鍵(candidate key:可以惟一標識一條記錄的最小屬性集服務器

    • 標識性:一個數據表的全部記錄都具備不一樣的候選鍵
    • 最小性:候選鍵的任何子集都不能惟一標識一個記錄
    • 非空性:不能爲空
    • 候選鍵是沒有多餘屬性的超鍵

  三、主鍵(主碼、primary key)某個可以惟一標識一條記錄的最小屬性集網絡

    • 惟一性:一個數據表只能有一個主鍵
    • 標識性:一個數據表的全部記錄都具備不一樣的主鍵取值
    • 非空性:不能爲空
    • 選取某個候選鍵爲主鍵

  四、外鍵(foreign key):子數據表中出現的父數據表的主鍵,稱爲子數據表的外鍵。函數

  五、代理鍵:當不適合用任何一個候選鍵做爲主鍵時(如數據太長等),添加一個沒有實際意義的鍵做爲主鍵,這個鍵就是代理鍵。(如經常使用的序號一、二、3)性能

  六、天然鍵:天然生活中惟一可以標識一條記錄的鍵(如身份證)spa

 

  下面就來看一下常見的幾種關係數據庫範式吧。

 

1、第一範式(1NF)

  要求:

  •   每個屬性都不能再分割,都是原子項。

  第一範式是關係型數據表的基本要求,可是如何判斷一個屬性可否再分割呢?這沒有統一的標準,須要依照需求肯定。好比,咱們要設計一個網絡遊戲後臺所用的數據庫,其中有一個數據表,記錄有關於擊殺怪物所得到的金錢:

編號

怪物名

掉落金錢

1

巨熊

100

   這個表格看上去並無什麼問題。每個屬性項都是」不可分割「的,因此符合第一範式。可是,若是咱們但願把玩家擊殺怪物以後得到的金錢分紅兩部分,一部分是固定收益,另外一部分是一個隨機的浮動收益(好比和玩家幸運值有關)。則這張表格中的」掉落金錢「項就不是」不可分割「了,也就不符合第一範式了。若是有這種需求,咱們就能夠把」掉落金錢「分割爲」固定金錢「和」浮動金錢「兩部分。以下所示:

編號

怪物名

固定金錢

浮動金錢

1

巨熊

80

20

  這樣分割以後,使得每一項都不能再分割,從而使得數據表知足第一範式。 

  知足第一範式的數據表有什麼好處呢?

  1. 1NF保證了數據庫的每一列都是不一樣的。每一列的數據彼此沒有任何交集。
  2. 這樣作首先減小了數據的冗餘,節省存儲空間。若是不知足第一範式,一些數據項有可能包含相同的」子項「,形成存儲空間的浪費。
  3. 其次,每一列沒有重複的數據意味着不須要考慮數據更新的同步問題。不用擔憂在一列中更新了數據,還要在另外一列作相應修改。
  4. 另外,每一列的數據不可再分,在某些狀況下少了數據訪問的層數,提升數據訪問速度。

 

2、第二範式(2NF)

  要求:

  • 知足第一範式
  • 非主鍵屬性均徹底依賴於主鍵

   非主鍵屬性和主鍵能夠有什麼關係?一、徹底依賴。二、部分依賴。三、不依賴(不要緊)。顯然第三種狀況下,這個屬性就不該該放在這張數據表中。因此2NF要求非主鍵屬性徹底依賴於主鍵,就是在消除非主鍵屬性對主鍵的部分函數依賴。既然是部分函數依賴,暗含着說主鍵是一個複合鍵(由多個屬性組成的鍵)。若是某個非主鍵屬性只和主鍵中的一部分有關(部分函數依賴),則不符合第二範式。舉例,網絡遊戲的用戶數據表:

玩家用戶名

角色名

角色職業

上次登陸時間

 Alice

superman

wizard

2013-11-4 

  若是咱們的遊戲容許一個玩家擁有多個角色,則在這張表中「玩家用戶名」和「角色名」構成複合主鍵,惟一標識一條記錄。表中的「角色職業」,與玩家用戶名和角色名均相關,爲徹底依賴於主鍵。而「上次登陸時間」僅和「玩家用戶名」相關,而與角色名無關。因此「上次登陸時間」部分函數依賴於主鍵。本關係不符合2NF。

  要將上表轉換爲符合2NF的結構也很簡單,只要把部分函數依賴的部分抽出來,組成新的表便可。以下所示:

玩家用戶名

角色名

角色職業

Alice

superman

wizard

 

玩家用戶名

上次登陸時間

Alice

2013-11-4

  符合2NF能給咱們帶來什麼好處呢?2NF消除了屬性對主鍵的部分函數依賴。

  首先,2NF能夠在必定程度上消除冗餘,節省存儲空間。

  若是存在部分函數依賴,則可能存在數據冗餘。在多條記錄中,主鍵中的某一個屬性多是同樣的,而若是有其餘數據項函數依賴於這個不變的屬性,則這些數據項也將是同樣的。好比在上面例子中,在修改以前的表中,若是有多個角色名對應一個玩家用戶名,則會有多條數據。它們具備同樣的用戶名和不一樣的角色名。因爲上次登陸時間僅依賴於玩家用戶名,因此在這多條記錄中,上次登陸時間也都是相同的,形成了冗餘。

  其次,2NF簡化了表的邏輯關係,使得表的結構更加清晰。

 

3、第三範式(3NF)

  要求:

  • 知足第1、二範式
  • 全部非主鍵屬性之間沒有函數依賴關係

  3NF在2NF的基礎上,進一步消除非主鍵屬性之間的函數依賴關係。實質上,也是消除非主鍵屬性中的傳遞依賴。更進一步地說,若是兩個數據表有關係。那麼這兩個數據表中的非主鍵屬性必須是不一樣的。若是存在一個非主鍵屬性A,存在於兩張表中。則在某張表中,A依賴於外鍵,從而不符合3NF。好比網絡遊戲中拍賣行的數據,能夠按照下面的表格進行存儲:

玩家姓名

物品名

單價

數量

總金額

Alice

治療藥劑

50

10

500

  在這個表格中,「總金額」項能夠經過「單價」和「數量」運算得出,存在函數依賴關係,不知足3NF。

  要將這個表格修改成知足3NF的要求,只須要從表中刪除「總金額」便可。在另一些狀況中,能夠將函數依賴關係涉及到的項單獨抽出來組成新的表,須要具體狀況具體分析。

  3NF的優勢很明顯,能夠減小數據冗餘,節省存儲空間。既然存在函數依賴,某些數據項就可以經過其餘數據項計算得出,極可能存在數據冗餘。值得注意的是,在一些狀況下,存在這種數據冗餘的表格是有意義的。若是在表格中存儲着某些運算的結果,咱們在使用這些結果時就不用進行運算了,節省了運算時間,是一種「空間換時間」的作法。從這裏也能夠看出,應用範式並不可以保證最好的效果,須要根據應用需求進行合理取捨。

  

4、BC範式(boyce-codd範式,BCNF)

  要求:

  • 知足1NF、2NF、3NF 
  • 全部屬性(包含主鍵屬性和非鍵主屬性)都不傳遞依賴於任何候選鍵

  BC範式在3NF的基礎上,要求主鍵屬性也不能傳遞依賴於任何候選鍵。當主鍵是複合鍵是,主鍵的某個屬性可能會依賴於某個候選鍵。此時,關係可以符合3NF,由於並非「非主鍵」屬性依賴於某個非主鍵屬性。但此關係並不符合BC範式。例如,在以房間爲組織方式的遊戲中,咱們記錄某個玩家、房間和房主的關係。

房主ID

房間ID

玩家ID

Alice

123

Bob

  表中的依賴關係有:

  1. (玩家ID,房間ID)-> 房主ID
  2. 房主ID -> 房間ID
  3. (玩家ID,房主ID)-> 房間ID

  同時,表中的候選鍵有(玩家ID,房間ID)、(玩家ID,房主ID)。好比,咱們選擇主鍵爲(玩家ID,房間ID),那麼,房間ID就是主鍵的一個屬性。而在依賴關係2中,房間ID依賴於房主ID,房主ID是候選鍵(玩家ID,房主ID)的一個屬性。那麼,首先,因爲房間ID不是候選鍵屬性,因此此表並無違反3NF。可是因爲房間ID和房主ID存在依賴關係,因此知足「主鍵屬性傳遞依賴於某個候選鍵」的條件,因此此表不符合BC範式。

  要把上表修改成知足BC範式的形式,只要把它進行合理拆分便可。

房間ID

玩家ID

123

Bob

 

房間ID

房主ID

123

Alice

   BC範式的好處是進一步消除了表中的依賴關係,減小了冗餘。例如在上例中,若是咱們採用未修改的版本,若是想要存儲一個10個玩家(不含房主)的房間,就須要10條這樣的記錄才能夠。

  

5、第四範式

  要求:

  • 知足1NF、2NF、3NF
  • 表中不能包含一個實體的兩個或多個多值屬性

  所謂多值屬性,指的是某個屬性能夠包含多個值。這個屬性的(多個)取值,被另外一個屬性決定。也就是說,一旦肯定了某個屬性,另外一個屬性的多個取值就一塊兒肯定了。第四範式在第三範式的基礎上,消除多值依賴。所謂多值依賴,指的是一組值(多值屬性)依賴於另外一個屬性。函數依賴是一對一的關係,多值依賴是一對多的關係。這個理解起來我感受有點彆扭,可能個人理解也有誤差,說出來和你們一塊兒探討一下。

  好比,咱們要在數據庫中保存玩家的角色技能信息,這裏咱們容許一個玩傢俱備多個角色,一個角色具備多個技能:

 

玩家ID

角色名

技能

Alice

superman

Fire ball

  首先,這個表只有一個候選鍵(玩家ID、角色名、技能)。因此確定符合3NF。進一步觀察一下,玩家ID是一個單值屬性。角色名就是一個多值屬性了,由於一個玩家ID能夠對應多個角色名。角色名在表中看起來是一項,這是因爲受制於具體數據庫提供的功能。邏輯上,咱們拿到一個玩家ID,能夠肯定的是,這個玩傢俱備某些角色,是一個一對多的關係,是多值依賴。角色名是一個多值屬性。一樣的,一個角色也對應着多個技能,這也是多值依賴。技能也是一個多值屬性。顯然,這個表並不符合4NF。

  這個表有什麼問題呢?

  首先,數據冗餘大,若是一個玩家有好幾個具備Fire Ball技能的角色,這個技能項就要重複保存幾回。

  其次,增、刪、改都比較複雜,好比咱們要刪除Fire Ball技能,那麼,咱們要刪除這個玩家全部具備Fire Ball技能的表項。

  要將上表修改成符合4NF的表,只須要將多值依賴進行合理映射便可:

玩家ID

角色名

Alice

superman

 

角色名

技能

superman

Fire ball

  這兩個表都符合4NF。

  能夠看出,4NF的使用能夠下降數據冗餘,而且減小數據處理複雜度

  

6、第五範式

要求:

  • 知足1NF、2NF、3NF、4NF
  • 若是將表中的多元關係分解一個一個的二元關係,必定會丟失信息

  第五範式在4NF的基礎上,進一步消除依賴。第五範式的要求明,若是不用這個表就不能正確說明數據之間的聯繫。因此符合5NF的表已經沒有任何多餘依賴的存在了。因此第五範式是一個比較理想的範式。好比咱們存儲玩家對戰和其發生地點:

玩家1

玩家2

對戰地點

Alice

Lisa

競技場1

Alice

Bob

競技場2

Bob

Lisa

競技場1

  如今,咱們把它拆分紅三個二元關係:

玩家1

玩家2

Alice

Lisa

Alice

Bob

Bob

Lisa

 

玩家1

對戰地點

Alice

競技場1

Alice

競技場2

Bob

競技場1

 

玩家2

對戰地點

Lisa

競技場1

Bob

競技場2

Lisa

競技場1

 

  單獨看這三個子表,咱們能夠得出如下結論:

  1. Alice和Bob對戰過
  2. Alice在競技場1和競技場2都進行過對戰
  3. Bob在競技場1和競技場2都進行過對戰(結合第2、三個表)

 

  從這三個獨立的結論,咱們沒法得知Alice和Bob究竟在那個競技場進行的對戰,也就是發生了信息丟失。因此上邊那個表是符合5NF的。

 

  好了,6個範式都看完啦,簡單總結一下:

範式等級

說明

1NF

每一列都是原子項,不可分割

2NF

非主鍵屬性均徹底依賴於主屬性,消除部分依賴

3NF

全部非主鍵屬性之間沒有依賴關係,消除傳遞依賴

BCNF

全部屬性均不傳遞依賴於任何候選鍵

4NF

表中不包含超過一個多值屬性,消除多值依賴

5NF

將表拆分爲二元關係,必定會損失信息

 

 

  感謝您看到這裏!但願對您有一點幫助,歡迎批評和討論! ^_^

 

  其餘博客:

  基礎中的基礎(二):C/C++ 中 const 修飾符用法總結

  基礎中的基礎(一):簡單排序算法總結(附代碼)

相關文章
相關標籤/搜索