數據庫模型設計——關系的實現


在實體關系模型中,我們知道有三種關系:一對一、一對多、多對多。這只是概念上的關系,但是在真實的關系數據庫中,我們只有外鍵,並沒有這三種關系,那么我們就來說一說在關系數據庫管理系統中,怎么實現這三種關系。

一對多

這里先講解一對多,因為這個關系最簡單。一對多和多對一是一回事,所以就不再提多對一這個詞。一對多的概念是一個對象A會對應多個對象B,而從B的角度看,一個對象B只會對於一個對象A。比如說班級和學生就是一對多關系。一個班級對應多個學生,一個學生只會對於一個班級。

一對多的關系之所以說簡單,是因為RDBMS的外鍵其實就是表示一對多關系。對於一對多關系,我們只需要在“多”的這個表中建立“一”的外鍵關聯即可,而“一”這邊的表不需要做任何修改。比如前面說到的班級學生關系。班級表不變,學生表增加班級Id作為外鍵。

多對多

多對多的關系在數據庫設計時比一對一要常見,所以這里先說說多對多。多對多是一個對象A對應多個對象B,從B角度看,一個對象B也會對應多個對象A。比如說學生和課程的關系就是多對多關系。一個學生會學習多門課程,一門課程會有多個學生來選修。

在RDBMS中,必須使用中間表來表示多對多的關系。中間表我們可以分成兩種,一種是純粹表示關系的中間表,一種是表示中間實體的中間表。

純粹表示關系的中間表很簡單,只需要兩列:AID和BID,AID以外鍵關聯到A表的主鍵,BID以外鍵關聯到B表的主鍵,然后這兩個列組成聯合主鍵。這個中間表純粹是表示多對多關系而存在,在業務上不會有對應的實體與之對應。比如前面提到的學生和課程的關系,如果我們只需要知道哪些學生上哪些課,哪些課有哪些學生選,不需要有更多的信息的情況下,我們就可以建立“學生課程”中間表,里面只有學生ID和課程ID兩個字段。

中間實體是在純粹的中間關系表的基礎上,加上了更多的屬性,從而形成了一個新的實體。比如前面提到的學生和課程的關系,如果我們需要記錄學生選課的時間、學生選擇這門課程后的考試成績,那么我們就像建立一個“選課”實體,該實體具有如下屬性:

  • 選課ID,主鍵
  • 學生ID,與學生表做外鍵關聯
  • 課程ID,與課程表做外鍵關聯
  • 選課時間,DateTime類型
  • 考試成績,記錄選修該課程后考試的最終成績

這就是一個中間實體,已經完全脫離了普通的多對多關系中間表,而變成一個實體的形式的存在,所以按照前面博客中講到的主鍵設計的原則,我們可以單獨建立一個選課ID的列作為數據庫的主鍵,該主鍵本身並沒有業務含義。

一對一

一對一概念上是說一個對象A最多對應一個對象B,從B角度看,也是一個對象B最多對應一個對象A。比如說班主任(教師)和班級的關系,一個班主任最多管理一個班級,一個班級也最多只有一個班主任。

一對一的關系在數據庫設計中,是使用的最少的關系,因為一般來說,如果兩個實體是一對多關系,那么我們也可以把這兩個實體合並成一個實體。但是在設計中,我們仍然會遇到兩個完全不同的實體,之間存在一對一關系。

一對一的RDBMS實現是在其中的一個表上建立外鍵指向另一個表,同時在該外鍵列上建立唯一約束。比如前面說到的班主任和班級關系,我們可以在班級表建立班主任字段,然后再在該字段建立唯一約束。因為每個班都會有班主任,所以班主任字段是不允許為空的。一個教師可以當某個班的班主任,也可以不當任和班的班主任,同時也不可能在班級表的班主任字段上出現兩次,所以最多就當一個班的班主任,所以該設計滿足需求。

那么我們可不可以反過來,在教師表中建立所管理的班級Id字段,指向班級表,並建立唯一約束呢?除了不滿足“每個班必然有一個班主任”這個業務約束外,其他都沒有問題。所以如果對於一對一的情況,如果那邊必須要求持有另一邊,則就在哪邊增加外鍵字段;如果沒有要求必須持有一個另一類實體的話,就哪邊添加外鍵列都行。

外鍵與索引

外鍵是一種約束,與索引的概念不一樣,只是大多數情況下,我們建立外鍵時,都會在外鍵列上建立對應的索引。外鍵的存在會在每一次數據插入、修改時進行約束檢查,如果不滿足外鍵約束,則禁止數據的插入或修改,這必然帶來一個問題,就是在數據量特別大的情況下,每一次約束檢查必然導致性能的下降。索引其實也有類似的問題,索引如果建多了,那么在插入刪除修改數據時也要去維護對應的索引,所以索引的存在也會導致數據操作變慢。

不過外鍵與索引的優點不同,外鍵只是保證數據的一致性,並不能給系統性能帶來任何好處,所以由於外鍵導致的插入數據變慢會隨着數據量的增長而越來越嚴重。而索引的目的是為了檢索數據更快,維護數據時導致的索引數據的變更,對性能的影響不會像外鍵那樣隨着數據量增長而變得嚴重(當然大數量時的索引樹維護會比小數據量的索引樹維護更麻煩,但至少不是像外鍵那樣)。

出於性能的考慮,如果我們的系統完全由我們開發的程序使用,而不需要提供數據庫給其他應用系統寫入數據,而且對性能要求較高,那么我們可以考慮在生產環境中不使用外鍵,只需要建立能夠提高性能的索引。由於整個數據庫的操作都是由我們開發的程序來完成的,所以我們程序可以在開發過程中做好各方面的一致性檢查,保證操作的數據是滿足外鍵約束的,而不需要真正的存在這樣一個外鍵約束。怎么做到這一點呢,首先,我們在建立數據庫時有多個腳本,包括創建表、創建初始化數據、創建索引、創建外鍵等,我們在開發和測試環境中,都把這些腳本運行了,以使開發測試環境中的數據庫是完整的,經過大量測試保證應用程序能夠維護數據之間的約束的情況下,那么我們在生產時,並不需要運行創建外鍵這個腳本文件,只需要創建表、初始化數據、創建索引等即可。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM