在上學的時候,數據庫是一門讓我比較頭大的課程。記得當時教材上淨是一些晦澀難懂的語言,沒有充足的實例來幫助理解。前一陣子在看《網絡遊戲服務器端編程》的過程當中,忽然對數據庫範式有了一些感受,在此總結一下,分享給你們。做者純菜鳥,即便總結這些基礎知識也不免有錯,但願給位大牛不吝賜教,謝謝!html
鍵(關係鍵)以及數據庫範式都是關係數據庫的概念。所謂關係鍵,指的是一個表中的一個(或一組)屬性,用來標識該表的每一行或與另外一個表產生聯繫。算法
數據庫的」範式「,指的是設計數據庫的規則。按照必定的規則設計出數據庫的表和關係,可以避免在一些狀況下的查詢出錯,並具備良好的結構。總的來講,隨着範式等級的提升,數據表屬性之間的依賴關係愈來愈小,數據冗餘愈來愈低。但同時,數據關係變得更加複雜,訪問一個具體數據的關係層次增長。因此像設計模式同樣,不該盲目追求範式等級,應根據具體需求來選擇範式。數據庫
咱們先來看一下幾種常見的數據庫關係鍵:編程
一、超鍵(super key):可以惟一標識一條記錄的屬性或屬性集。設計模式
二、候選鍵(candidate key):可以惟一標識一條記錄的最小屬性集服務器
三、主鍵(主碼、primary key):某個可以惟一標識一條記錄的最小屬性集網絡
四、外鍵(foreign key):子數據表中出現的父數據表的主鍵,稱爲子數據表的外鍵。函數
五、代理鍵:當不適合用任何一個候選鍵做爲主鍵時(如數據太長等),添加一個沒有實際意義的鍵做爲主鍵,這個鍵就是代理鍵。(如經常使用的序號一、二、3)性能
六、天然鍵:天然生活中惟一可以標識一條記錄的鍵(如身份證)spa
下面就來看一下常見的幾種關係數據庫範式吧。
1、第一範式(1NF)
要求:
第一範式是關係型數據表的基本要求,可是如何判斷一個屬性可否再分割呢?這沒有統一的標準,須要依照需求肯定。好比,咱們要設計一個網絡遊戲後臺所用的數據庫,其中有一個數據表,記錄有關於擊殺怪物所得到的金錢:
編號 |
怪物名 |
掉落金錢 |
1 |
巨熊 |
100 |
這個表格看上去並無什麼問題。每個屬性項都是」不可分割「的,因此符合第一範式。可是,若是咱們但願把玩家擊殺怪物以後得到的金錢分紅兩部分,一部分是固定收益,另外一部分是一個隨機的浮動收益(好比和玩家幸運值有關)。則這張表格中的」掉落金錢「項就不是」不可分割「了,也就不符合第一範式了。若是有這種需求,咱們就能夠把」掉落金錢「分割爲」固定金錢「和」浮動金錢「兩部分。以下所示:
編號 |
怪物名 |
固定金錢 |
浮動金錢 |
1 |
巨熊 |
80 |
20 |
這樣分割以後,使得每一項都不能再分割,從而使得數據表知足第一範式。
知足第一範式的數據表有什麼好處呢?
2、第二範式(2NF)
要求:
非主鍵屬性和主鍵能夠有什麼關係?一、徹底依賴。二、部分依賴。三、不依賴(不要緊)。顯然第三種狀況下,這個屬性就不該該放在這張數據表中。因此2NF要求非主鍵屬性徹底依賴於主鍵,就是在消除非主鍵屬性對主鍵的部分函數依賴。既然是部分函數依賴,暗含着說主鍵是一個複合鍵(由多個屬性組成的鍵)。若是某個非主鍵屬性只和主鍵中的一部分有關(部分函數依賴),則不符合第二範式。舉例,網絡遊戲的用戶數據表:
玩家用戶名 |
角色名 |
角色職業 |
上次登陸時間 |
Alice |
superman |
wizard |
2013-11-4 |
若是咱們的遊戲容許一個玩家擁有多個角色,則在這張表中「玩家用戶名」和「角色名」構成複合主鍵,惟一標識一條記錄。表中的「角色職業」,與玩家用戶名和角色名均相關,爲徹底依賴於主鍵。而「上次登陸時間」僅和「玩家用戶名」相關,而與角色名無關。因此「上次登陸時間」部分函數依賴於主鍵。本關係不符合2NF。
要將上表轉換爲符合2NF的結構也很簡單,只要把部分函數依賴的部分抽出來,組成新的表便可。以下所示:
玩家用戶名 |
角色名 |
角色職業 |
Alice |
superman |
wizard |
玩家用戶名 |
上次登陸時間 |
Alice |
2013-11-4 |
符合2NF能給咱們帶來什麼好處呢?2NF消除了屬性對主鍵的部分函數依賴。
首先,2NF能夠在必定程度上消除冗餘,節省存儲空間。
若是存在部分函數依賴,則可能存在數據冗餘。在多條記錄中,主鍵中的某一個屬性多是同樣的,而若是有其餘數據項函數依賴於這個不變的屬性,則這些數據項也將是同樣的。好比在上面例子中,在修改以前的表中,若是有多個角色名對應一個玩家用戶名,則會有多條數據。它們具備同樣的用戶名和不一樣的角色名。因爲上次登陸時間僅依賴於玩家用戶名,因此在這多條記錄中,上次登陸時間也都是相同的,形成了冗餘。
其次,2NF簡化了表的邏輯關係,使得表的結構更加清晰。
3、第三範式(3NF)
要求:
3NF在2NF的基礎上,進一步消除非主鍵屬性之間的函數依賴關係。實質上,也是消除非主鍵屬性中的傳遞依賴。更進一步地說,若是兩個數據表有關係。那麼這兩個數據表中的非主鍵屬性必須是不一樣的。若是存在一個非主鍵屬性A,存在於兩張表中。則在某張表中,A依賴於外鍵,從而不符合3NF。好比網絡遊戲中拍賣行的數據,能夠按照下面的表格進行存儲:
玩家姓名 |
物品名 |
單價 |
數量 |
總金額 |
Alice |
治療藥劑 |
50 |
10 |
500 |
在這個表格中,「總金額」項能夠經過「單價」和「數量」運算得出,存在函數依賴關係,不知足3NF。
要將這個表格修改成知足3NF的要求,只須要從表中刪除「總金額」便可。在另一些狀況中,能夠將函數依賴關係涉及到的項單獨抽出來組成新的表,須要具體狀況具體分析。
3NF的優勢很明顯,能夠減小數據冗餘,節省存儲空間。既然存在函數依賴,某些數據項就可以經過其餘數據項計算得出,極可能存在數據冗餘。值得注意的是,在一些狀況下,存在這種數據冗餘的表格是有意義的。若是在表格中存儲着某些運算的結果,咱們在使用這些結果時就不用進行運算了,節省了運算時間,是一種「空間換時間」的作法。從這裏也能夠看出,應用範式並不可以保證最好的效果,須要根據應用需求進行合理取捨。
4、BC範式(boyce-codd範式,BCNF)
要求:
BC範式在3NF的基礎上,要求主鍵屬性也不能傳遞依賴於任何候選鍵。當主鍵是複合鍵是,主鍵的某個屬性可能會依賴於某個候選鍵。此時,關係可以符合3NF,由於並非「非主鍵」屬性依賴於某個非主鍵屬性。但此關係並不符合BC範式。例如,在以房間爲組織方式的遊戲中,咱們記錄某個玩家、房間和房主的關係。
房主ID |
房間ID |
玩家ID |
Alice |
123 |
Bob |
表中的依賴關係有:
同時,表中的候選鍵有(玩家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、第四範式
要求:
所謂多值屬性,指的是某個屬性能夠包含多個值。這個屬性的(多個)取值,被另外一個屬性決定。也就是說,一旦肯定了某個屬性,另外一個屬性的多個取值就一塊兒肯定了。第四範式在第三範式的基礎上,消除多值依賴。所謂多值依賴,指的是一組值(多值屬性)依賴於另外一個屬性。函數依賴是一對一的關係,多值依賴是一對多的關係。這個理解起來我感受有點彆扭,可能個人理解也有誤差,說出來和你們一塊兒探討一下。
好比,咱們要在數據庫中保存玩家的角色技能信息,這裏咱們容許一個玩傢俱備多個角色,一個角色具備多個技能:
玩家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、第五範式
要求:
第五範式在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 |
單獨看這三個子表,咱們能夠得出如下結論:
從這三個獨立的結論,咱們沒法得知Alice和Bob究竟在那個競技場進行的對戰,也就是發生了信息丟失。因此上邊那個表是符合5NF的。
好了,6個範式都看完啦,簡單總結一下:
範式等級 |
說明 |
1NF |
每一列都是原子項,不可分割 |
2NF |
非主鍵屬性均徹底依賴於主屬性,消除部分依賴 |
3NF |
全部非主鍵屬性之間沒有依賴關係,消除傳遞依賴 |
BCNF |
全部屬性均不傳遞依賴於任何候選鍵 |
4NF |
表中不包含超過一個多值屬性,消除多值依賴 |
5NF |
將表拆分爲二元關係,必定會損失信息 |
感謝您看到這裏!但願對您有一點幫助,歡迎批評和討論! ^_^
其餘博客: