數據庫設計(三範式,冗餘字段,逆範式)


數據庫設計(三範式,冗餘字段,逆範式)

  在設計數據庫的時候,應該注意一下什麼呢?首先來看一張表。

學生成績表     

      姓名         性別         java成績         c成績         班級  
張三 90 80 一班
李四 80 90 一班
楊過 90 80 一班


  思考:上面這張表在設計上會出現什麼問題?
  

  作爲初學者的我看到這章表,我的回答是不會出問題,其實從現實生活中來講,這的確沒什麼問題的,記得念中學的時候,每次考完試,心裏都很着急,急什麼呢?當然是成績,想想那個時候老師又是怎樣把你的成績信息給列出來的呢?是不是以這樣的方式,每個班,甚至整個學校的學生成績都是使用一張表來列出來的,而我們每個人的成績利用該表中的一行數據來表示的,其中包括一個學生的學號,姓名,班級,成績以及排名等等。而這裏我們只是專業化成了數據庫,一個班級的學生成績變成了數據庫中的一張表,而每個學生的成績變成了表中的一條記錄而已,所以認爲沒什麼問題。但是對數據庫的設計來講,概念就不一樣了,這樣設計就會很容易出現很多問題。會出現一下什麼問題呢。比如像增加異常,刪除異常,更新異常等等,下面是幾個例子。

  eg1:在增加數據的時候,可能發生錯誤。這叫增加異常    

姓名   性別     java成績     C成績     班級  
  張三   90 80 一班
  李四   80 90 一班
  楊過   90 80 一班
  小龍女   100 70 1班

  再仔細看上面這張表,在插入最後一條數據的時候,其中插入的班級和前面的不同,即“1班”,這從業務上來講,當然沒什麼問題,但是從數據庫的角度來講,確是兩個完全不同的概念,你可以認爲是數據庫本身太笨了吧,所以這個時候插入的數據,會給我們帶來不必要的錯誤,這種錯叫做增加異常。

  eg2:在刪除數據時,可能會刪除相關的其它數據,這叫刪除異常
這句話怎麼理解呢?同樣,看上面eg1的表,如果我們現在要指定刪除班級爲“一班”的班級怎麼辦?這個時候我們使用delete 學生成績表 where 班級='一班' 的話,就刪除了班級='一班'的這些記錄,這個時候,不是也給我們帶來了不必要的後果嗎?這就是刪除異常。

  eg3:在更新數據的時候,可能會有數據沒有更新到。這叫更新異常。 

姓名   性別     java成績     C成績     班級  
  張三   90 80 1班
  李四   80 90 1班
  楊過   90 80 一班

  那如何理解更新異常呢?先了解上面表在做什麼吧,上面表是在修改班級,我想把班級名稱全部改成“1班”,這個時候我會使用update語句來一條一條的修改,但是如果數據有很多很多的話,這個時候我們有可能忽略了某個地方,導致沒有修改到,所以在我執行某型操作的時候,就會出現數據與我們想象的不一致,這種結果就是所謂的更新異常導致的。上面舉了幾個例子,說明了在數據庫中是很容易出現問題的,而這些問題從業務上來講,我們很難查找出來,那導致這樣的問題原因是什麼呢?有兩點:

  1.看上面的表,把他們的數據全部耦合到一起了。
  2.因爲我這樣耦合的設計,導致產生了許多重複的數據,比如班級列,我就添加了三條一模一樣的,也就是一班。解決方法:根據實體和關係,我們可以把他們保存在不同的表中,然後可以利用一個外鍵,來指向我們所需要的數據。據上面例子,我們可以建立兩張表:

表1:

  班級     班級編號  
  一班    001 
  二班    002 

表2:

  學號     姓名     班級編號  
  0103     張三       001  
  0104         李四          001
      0201       楊過          002
      0202      小龍女          002

  這張表,就是把班級和學生信息分開來保存了,這個時候,班級和學生之間的關係是一對多,所以在數據庫設計的時候,我們可以將一對多中,多的那一方設置一個外鍵列,這裏當然是學生是多的這方,所以我們在表中有一列叫做“班級編號”的外鍵列,然後利用外鍵列去引用我們的班級表中的“班級編號”列,從而建立起他們一件的那種一對多的關係。上面的問題是解決了,但是在以後我相信還會遇到相同的問題,也就是會遇到什麼增加,刪除或更新異常等,這就代表了以後的數據“難以維護”。所以我們要對數據庫進行適當的設計,纔可以大大的增加可維護性。那麼進行數據庫設計,有六個範式,一般說來,數據庫只需滿足第三範式(3NF)就行了。什麼是範式呢?爲了將各種信息進行有效的分類整理,就設計了一套行之有效的數據庫設計原則,這叫做範式,英文normal forms,意思是規範化表。也表示將表進行分類處理,這個過程就叫做規範化。簡單理解,規範化表的過程,就是將數據進行分類的過程。下面說說這三個範式。

  1 第一範式(1NF)
  在任何一個關係數據庫中,第一範式(1NF)是對關係模式的基本要求,不滿足第一範式(1NF)的數據庫就不是關係數據庫。所謂第一範式(1NF)是指數據庫表的每一列都是不可分割的基本數據項,同一列中不能有多個值,即實體中的某個屬性不能有多個值或者不能有重複的屬性。如果出現重複的屬性,就可能需要定義一個新的實體,新的實體由重複的屬性構成,新實體與原實體之間爲一對多關係。在第一範式(1NF)中表的每一行只包含一個實例的信息。例如,對於員工信息表,不能將員工信息都放在一列中顯示,也不能將其中的兩列或多列在一列中顯示;員工信息表的每一行只表示一個員工的信息,一個員工的信息在表中只出現一次。簡而言之,第一範式就是無重複的行,並且列不可再分。

  2 第二範式(2NF)
第二範式(2NF)是在第一範式(1NF)的基礎上建立起來的,即滿足第二範式(2NF)必須先滿足第一範式(1NF)。第二範式(2NF)要求數據庫表中的每個實例或行必須可以被惟一地區分。爲實現區分通常需要爲表加上一個列,以存儲各個實例的惟一標識。員工信息表中加上了員工編號(emp_id)列,因爲每個員工的員工編號是惟一的,因此每個員工可以被惟一區分。這個惟一屬性列被稱爲主關鍵字或主鍵、主碼。第二範式(2NF)要求實體的屬性完全依賴於主關鍵字。所謂完全依賴是指不能存在僅依賴主關鍵字一部分的屬性,如果存在,那麼這個屬性和主關鍵字的這一部分應該分離出來形成一個新的實體,新實體與原實體之間是一對多的關係。爲實現區分通常需要爲表加上一個列,以存儲各個實例的惟一標識。簡而言之,第二範式就是非主鍵列必須依賴於主鍵列。第二範式(2NF)值得注意的是:“NF2要求在數據庫設計時,每個表中的信息,只能是自己實體所擁有的信息。”

  eg:屬性1必須依賴於屬性2:屬性1,一定是屬性2所代表的實體“天生”具有的。 

  學號     姓名     興趣1     興趣2  
1 a 打球   打豆豆
2 b 開車  開玩笑

   對這張表來說就是:姓名必須依賴於學號:姓名,一定是學號所代表的實體“天生”具有的如果想這張表不是屬於學號所代表的實體,即學生,那麼就應該將學生信息和興趣分開來建表保存。數據庫設計時,基本上都要滿足NF2.那什麼時候會違反NF2呢? 有一個需求,要求查詢:學號,姓名,班級名稱。由於學生姓名和班級名稱分開在2箇中,所以在查詢時,必須使用表連接。代碼:select * from 班級表 c , 學生表 s where c.班級編號=s.班級編號。但是表連接會讓計算機做大量的匹配和計算,所以是比較消耗資源(資源主要是指CPU和內存)。爲了提高效率,所以可以違反NF2,將表格如下:    

班級表
班級編號 班級名稱

 

              學生表  
   學號     姓名      班級編號     班級姓名   

  現在查詢就只需要查詢一個表了,從而避免了表連接!學生表中的“班級名稱”是第2次出現,所以叫做“冗餘字段”,這種設計方法叫做“逆範式”!在本質上,實際上就是犧牲空間,換取時間。  

  3 第三範式(3NF)

  在滿足了第一範式和第二範式的基礎只上,可以滿足第三範式,第三範式簡而言之,就是非主鍵列之間是相對獨立的。先看一張表。

 

  學號     姓名     出生日期     生肖  
1 張三 1980-01-02
2 李四 1983-04-02
3 王五 1988-11-02

生肖表 

  生肖編號     生肖名稱  
1
2

  這裏的生肖其實是和時間有關係了,可以通過時間來確定生肖是什麼,所以這裏的生肖完全可以忽略不計,一般這樣設計是爲了減輕數據庫的計算壓力,所以才保留此字段的,也就是前面提到的“冗餘字段”,逆範式。所以由此可以推出3NF是完全可以違反的。最後總結一下前三個範式那些必須滿足:

  NF1 行不可重複,列不可再分    -   必須滿足
  NF2 非主鍵列必須依賴於主鍵列    - 必須滿足
  NF3 非主鍵列之間必須相互獨立 -   NF3可以不滿足

發佈了6 篇原創文章 · 獲贊 9 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章