如何深入理解關係型數據庫中的三大範式

該文章,GitHub已收錄,歡迎老闆們前來Star!

GitHub地址: https://github.com/Ziphtracks/JavaLearningmanual

數據庫範式


一、什麼是數據庫範式

設計關係數據庫時,遵從不同的規範要求,設計出合理的關係型數據庫,這些不同的規範要求被稱爲不同的範式,各種範式呈遞次規範,越高的範式數據庫冗餘越小。

範式來自英文Normal form,簡稱NF。要想設計—個好的關係,必須使關係滿足一定的約束條件,此約束已經形成了規範,分成幾個等級,一級比一級要求得嚴格。滿足這些規範的數據庫是簡潔的、結構明晰的,同時,不會發生插入(insert)、刪除(delete)和更新(update)操作異常。

二、數據庫範式分類

目前關係數據庫有六種範式:第一範式(1NF)、第二範式(2NF)、第三範式(3NF)、巴斯-科德範式(BCNF)、第四範式(4NF)和第五範式(5NF,又稱完美範式)。滿足最低要求的範式是第一範式(1NF)。在第一範式的基礎上進一步滿足更多規範要求的稱爲第二範式(2NF),其餘範式以次類推。一般來說,數據庫只需滿足第三範式(3NF)就行了。

三、數據庫三大範式剖析

3.1 第一範式(1NF)

第一範式強調每一列都是不可分割的原子數據項。

說到原子這個詞,肯定有小夥伴就先到了原子性問題,其實這麼想也是沒有錯的。那就讓我帶你們去剖析一下第一範式。

首先,我用Excel表格模擬數據庫中的表,並在表中填入了一些數據。如下:

image-20200613164428707

當你看到這些數據的時候,是否有些數據讓你感到不適?我的答案,是的。當我看到系名/系主任這一列數據的時候感覺這並不合符我們數據庫的設計理念,因爲它完全可以拆分爲兩個列的。其實每一個人的思想中的已經有了這個範式要求的概念,只是你並不知道這個概念叫做第一範式。

如果有的小夥伴說,這些數據都讓感到不適,那我就在這裏誇上你一句,你很聰明。但是請你跟緊我的思路,我會一步一步的將數據落實到範式中!

表1顯然不遵循第一範式,那我們就把它修改一下,讓其遵循第一範式的要求。

image-20200613164455095

系名/系主任的列拆分成了兩個列系名系主任後,很明顯改數據已經遵循的第一範式的要求。再來看看這張表2,聰明的你是不是第一眼又發現了問題呢?

存在的問題:

  • 存在非常嚴重的數據冗餘,姓名、系名、系主任
  • 添加數據問題:當在數據表中添加一個新系和系主任時,比如:在數據表中添加高主任管理化學系。你會發現添加之後,在一個數據表中就會多出來了高主任和化學系,而這兩個數據並沒有對應哪個學生,顯然這時不合法的數據。
  • 刪除數據問題:如果Jack同學畢業多年了,我們數據表中沒有必要在留Jack相關的數據了,就會想到把Jack相關的刪除掉。當你在表2的表結構中刪除了Jack相關數據,你會發現整個劉主任和管理系以及會計和酒店管理都消失了,難道數據表中沒有這些數據就證明這個學校沒有它們嗎?顯然這更加離譜了!

瞭解了只遵循第一範式帶來的麻煩,我們就需要去看一下第二範式是怎麼定義的,是否能解決第一範式留下來的問題!

3.2 第二範式(2NF)

第二範式在1NF的基礎上,非屬性碼的屬性必須完全依賴於主碼。(在1NF基礎上消除非屬性碼的屬性對主碼的部分函數依賴)

看到第二範式的概念,現在你應該是一個不懂的狀態。那讓我帶你瞭解幾個概念吧,這樣你就會懂了!

函數依賴(完全、部分、傳遞)

函數依賴: A - > B,如果通過A屬性(或屬性組)的值可以確定唯一B屬性的值,則可以成爲B依賴於A(- >符號是確定關係)。例如:可以通過學號來確定姓名,可以通過學號和課程來確定該課程的分數等等

  • 完全函數依賴: A - > B,如果A是一個屬性組,則B屬性的確定需要依賴A屬性組中的所有屬性值。例如:分數的確定需要依賴於學號和課程,而學號和課程可以稱爲一個屬性組。如果有學號沒有課程,我們只知道是誰的分數,而不知道是那一學科的分數。如果有課程沒有學號,那我們只知道是哪一個學科的分數,而不知道是誰的分數。所以該屬性組的兩個值是必不可少的。這就是完全函數依賴。
  • 部分函數依賴: A - > B,如果A是一個屬性組,則B屬性的確定需要依賴A屬性組中的部分屬性值。例如:如果一個屬性組中有兩個屬性值,它們分別是學號和課程名稱。那姓名的確定只依賴這個屬性組中的學號,於課程名稱無關。簡單來說,依賴於屬性組的中部分成員即可成爲部分函數依賴。
  • 傳遞函數依賴: A - > B - > C,傳遞函數依賴就是一個依賴的傳遞關係。通過確定A來確定B,確定了B之後,也就可以確定C,三者的依賴關係就是C依賴於B,B依賴於A。例如:我們可以通過學號來確定這位學生所在的系部,再通過系部來確定系主任是誰。而這個三者的依賴關係就是一種傳遞函數依賴。
候選碼、主屬性碼與非屬性碼
  • 碼: 如果在一張表中,一個屬性或屬性組,被其他所有屬性所完全函數依賴 ,則稱這個屬性(或屬性組)爲該表的候選碼,簡稱碼。然而碼又分爲主屬性碼和非屬性碼。例如:分數的確定沒有學號和課程是不行的,所以分數完全函數依賴於課程和學號。
  • 主屬性碼: 主屬性碼也叫主碼,即在所有候選碼挑選一個做主碼,這裏相當於是主鍵。例如:分數完全函數依賴於課程和學號。該碼屬性組中的值就有課程、學號和分數,所以我們要在三個候選碼中,挑選一個做主碼,那就可以挑選學號。
  • 非屬性碼: 除主碼屬性組以外的屬性,叫做非屬性碼。例如:在分數完全函數依賴於課程和學號時,其中學號已經讓我們選爲主碼。那麼我們就可以確定,除了學號以外的屬性值,其他的屬性值都是非屬性碼。也就是說在這個完全函數依賴關係中,課程和分數是非屬性碼。

當我們瞭解這些概念後,回過頭來再看2NF的概念:在1NF的基礎上,非屬性碼的屬性必須完全依賴於主碼(在1NF基礎上消除非屬性碼的屬性對主碼的部分函數依賴)

我們還使用分數完全函數依賴於學號和課程這個函數依賴關係。此關係中非屬性碼爲:課程和分數,主碼爲學號。梳理清楚關係後,遵循在1NF基礎上,非屬性碼的屬性必須完全依賴於主碼的第二範式。就需要繼續修改表結構了。遵循1NF和2NF的表結構如下:

image-20200613170300513

image-20200613170326468

正如你所看到的,我們把表2根據1NF和2NF拆分成了表3和表4。這時候你再看錶3,表3中的分數就完全函數依賴於表3中的學號和課程。表4中也挑選學號做主碼。雖然解決了數據冗餘問題,但是僅僅這樣還是不夠的,上述問題中其他的兩個問題並沒有得到解決!

存在的問題:

  • 數據刪除問題
  • 數據添加問題

注意: 在第二範式中存在的這兩個問題,就是在第一範式中存在問題的其中兩個並沒有得到解決。

既然第一範式和第二範式都沒有解決這兩個問題,那第三範式幫你解決!

3.3 第三範式(3NF)

第三範式在2NF基礎上,消除傳遞依賴。

說到傳遞依賴,那我們的數據表中還有哪些傳遞依賴呢?這時候你會發現表4中含有傳遞依賴的。表4中的傳遞依賴關係爲:姓名 - > 系名 - > 系主任。該傳遞依賴關係爲系主任傳遞依賴於姓名。再根據此傳遞依賴關係分析我們添加和刪除問題就漏洞百出了。消除傳遞依賴的辦法還是將表4進行拆分。拆分後的表結構如下:

image-20200613172237233

image-20200613172303711

當我們把表4拆分成表5和表6時,你再來分析添加和刪除問題就會有不一樣的結果。假設在數據表中添加高主任管理的化學系時,該數據只會添加到表6中,不會發生傳遞依賴而影響其他數據。那假設Jack同學畢業了,要將Jack同學的相關數據從表中刪除,這時我們需要刪除表6中的學號3數據和表3中的學號3數據即可,它們也沒有傳遞依賴關係,同樣不會影響到其他數據。

四、範式的表設計

在這裏我詳細講解了數據庫的三大範式,爲什麼一般我們只研究三大範式而不去延申至六大範式呢?在上面數據庫範式概念的時候,我也有講過。這裏我還需要強調一下!

數據庫六大範式,一級比一級要求得嚴格。各種範式呈遞次規範,越高的範式數據庫冗餘越小。範式即是對數據庫表設計的約束,約束越多,表設計就越複雜。表數據過於複雜,對於我們後期對數據庫表的維護以及擴展、刪除、備份等種種操作帶來了一定的難度。所以,在實際開發中我們只需要遵循數據庫前面的三大範式即可,不需要額外延申擴展。

注意: 在剖析三大範式的時候,最終版本的表結構就是表3 + 表5 + 表6。我需要在這裏說明一個問題,其實這樣設計表是可以的,但並不是很合理。因爲我們在建表的時候是有主鍵和外鍵約束的。這三張表中,第一列的表默認爲主鍵,其中主鍵爲學號還可以接收,如果主鍵爲系名那就佔用的空間變大了。在表的級聯查詢中會損耗性能。所以,一般我們在設計表的時候,是需要主外鍵約束的,而其主外鍵基本是都是佔用內容空間很小的數字。當你的表結構和需求滿足主鍵遞增時,則可以通過設置auto_increment參數來完成!

這裏如果不瞭解MySQL主外鍵約束的小夥伴,可以參考此文章MySQL基礎來查補缺漏知識點。


老闆們,記得我的Star哦!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章