參考
參考文章:https://zhuanlan.zhihu.com/p/20028672
本文的例子以及敘述思路來源於上文。
定義
三范式是對關系型數據庫表結構設計的一種規范制約,設計出的數據表如果滿足范式的標准,則稱某數據庫表滿足第一(二、三)范式。數字越大,標准越嚴格。且第一范式、第二范式、第三范式是一個遞進的過程,滿足第一范式后,才能去
評價是否滿足第二范式。
第一范式
每一個屬性都是不可再分割的,這是構成數據庫表的必要條件。換句話說,能放進數據庫里的表,都滿足第一范式。
摘一個圖過來
這種就不滿足第一范式。進貨不能作為屬性,需要拆分成進貨表,銷售也同樣如此。
第二范式
滿足一范式后,就可以將你抽象的設計具體化,可以將你的想法付諸實踐,形成具體的表結構,存進數據庫了。現有表結構:學生表,學生表的內容為
可以發現,每人每門課的成績,都會不厭倦地帶上系名、系主任等信息,很累贅、很繁瑣。
這樣設計表結構會給業務帶來什么影響呢?
1、數據冗余
2、插入異常——現在學校決定新建一個系了,還沒來及的招收學生,便無法將系信息單獨的插進去。
3、刪除異常——如果此時決定將一批學生的成績信息全部刪除,那么同時也將會刪除該學生所在系的相關信息,這不是我們想看到的。
4、修改異常——如果此時,李明想要轉系了,那么只要是關於李明的成績記錄。都需要修改系信息。
這個時候,我們就需要引入第二范式的概念了。
在第一范式的基礎上,清除了非主屬性對於碼的部分函數依賴。
- 函數依賴
如果A屬性的值確定,那么B屬性的值也確定,稱作B依賴於A。這樣來看可能有點繞,按照我們思維習慣,可以這么理解,A決定了B,所以A有主導權,B就依賴A。
上述表有哪些函數依賴呢?
姓名 依賴於 學號 (學號知道了,姓名也就知道了)
系主任 依賴於 學號 (學號知道了,系主任自然知道了)
分數 依賴於 (學號、課名) (知道課名,學號,必然知道分數了)
- 完全函數依賴
分數依賴於(學號、課名),只要在知道學號和具體哪一門課的前提下,才能知道分數,缺一不可,這就是完全依賴。
- 部分函數依賴
表面上姓名部分依賴於(學號,課名),但其實姓名只依賴於學號,這就叫部份依賴。
- 傳遞函數依賴
X 依賴於Y, Y依賴於 Z,在 Y不依賴於X的前提下, X依賴於Z
- 碼
碼可能是一個屬性,也可能是一個屬性組(多個屬性的組合)。如果碼確定了,那么屬性也確定了。哎~,這不就是主鍵嗎?
並不能這么說,比如一張表里有身份證、學號, 學號和身份證都能表示唯一性,知道任意一個,就可以鎖定到這個學生。
我們在選擇主鍵的時候,身份證和學號並不會都用,只會選擇其一。所以我們所說的主鍵其實是碼的一個子集。
- 主屬性
碼的一個成員
- 非主屬性
不是碼的成員。
現在可以來理解第二范式的定義了:是否存在非主屬性對碼的部分函數依賴。
判斷是否滿足第二范式,需要經過一下幾個步驟:
- 第一步驟
找到表中的碼,(學號、課名)
- 第二步驟
主屬性:學號、課名
- 第三步驟
非主屬性:姓名、系名、系主任、分數
- 第四步驟
分析非主屬性是否對碼有部份依賴
姓名,只依賴於學號,有部分依賴
系名,只依賴於學號,有部份依賴
系主任,只依賴於學號,有部份依賴
分數,依賴於學號、課程,沒有部份依賴
- 結論
目前的表結構,並不滿足第二范式,姓名、系名、系主任,這些非主屬性居然對碼有部分依賴,注定是要被踢出來的。
改造
分數表
學生表
分析:
我們從第二范式的定義入手,分析表屬性,將一張表拆分成了兩張表。仔細一看,從業務上將,無非就是將學生信息與學生成績拆分下來。
可是拆分的並不徹底,還是存在一些問題。
如果刪除了某個系所有學生信息,那么這個系的信息也會消失。系信息與學生信息耦合在一起。我們將一步改造這張表,使其滿足第三范式。
第三范式
第三范式在第二范式的基礎上,消除了非主屬性對於碼的傳遞函數依賴。
成績表已經沒有耦合,除了主碼,就剩一個分數字段了,且對碼沒有部份依賴,不需要改造。那我們重點分析一下成績表
分析
主碼:學號
主屬性:學號
非主屬性:姓名、系名、系主任
學號知道了,系名就知道了;系名知道了,系主任就知道了。
系主任依賴系名,系名依賴學號。存在非主屬性對於碼的傳遞依賴。
因此學生表不符合第三范式,進一步拆分:
學生表
系表
在經過多次拆分后,現有的三張表分別是:成績表、學生表、系表。解決了冗余、插入一場、修改異常、刪除異常等多種問題。
BCNF范式
BCNF范式的目的在於,消除主屬性對於碼的部分和傳遞函數依賴。
舉例:
某公司有若干倉庫,需要派人管理,一個管理員只能管理一個倉庫,各個倉庫可以存放相同的物品。(原文中用的是管理員名,但是名字可能會重復,所以把它換成工號。)
碼:(管理員工號,物品名)、(物品名,倉庫名)
主屬性:倉庫、管理員工號、物品名
非主屬性:數量
不存在非主屬性對碼的傳遞依賴、部份依賴,滿足第三范式。但是依然存在問題:
雖說一個倉庫只有一個管理員,且一個管理員只能管理一個倉庫,但是這個管理員可能會有變動,如果哪一天某個倉庫換了個管理員,那么這個倉庫有幾條物品記錄,就需要修改多少條數據。究其根本,還是因為耦合的問題。
BCNF范式,要求消除主屬性對於碼的部份依賴和傳遞依賴。倉庫名是一個主屬性,依賴於管理員工號,也依賴於物品名。那么就將倉庫和倉庫管理員拆分出來。
倉庫表
庫存表
總結
范式是一種規范,一種約束。但是在實際項目中,可能會出現各種各樣的情況,我們不必死守規范,而應當靈活變通。
按照范式來設計數據表,本質上就是一種解耦的過程。范式的好處就是,明確定義了這個耦合的程度,以及我們如何降低這個耦合。一范式,二范式、三范式是解耦的過程。BCNF范式是第二、第三范式的一種補充。
多說幾句,如果在工作中,我可能不會從范式的角度入手,而是從業務本身來設計數據表,例如第一個例子,有哪些是很少變化的,有哪些是經常變化的。系名、系主任這是綁定在一起的,是一個整體的概念,代表“系”,且很少變化。其次就是學生,學生除非跨年級、畢業,一般也不會變化,是一個整體的概念。最后是成績,學生可能有好幾門課,每門課都可以被多個人選,是多對多的概念,所以抽象出成績表,將學生與課程關聯起來。
不管是學習還是工作中,設計數據庫的時候可能會從常識的角度,或者從業務需求的角度入手。在我們設計出表后,需要進一步考慮其合理性,這個時候就可以換一個思維,從范式的角度來看這些表,結合實際情況做優化。
如有錯誤,懇請指出。