數據庫表設計(一對多,多對多) 【好】


http://www.mamicode.com/info-detail-1250282.html

 

做一個項目,必然是少不了數據庫設計的!在學習階段,基本都是單表。然而在實際開發過程中,一對多,多對多的表處處都是!簡單整理一下,一對多,多對多表如何設計整理一下思路:

       數據庫實體間有三種對應關系:一對一,一對多,多對多。

       一對一關系示例:

    • 一個學生對應一個學生檔案材料,或者每個人都有唯一的身份證編號。

       一對多關系示例:

    • 一個學生只屬於一個班,但是一個班級有多名學生。

       多對多關系示例:

    • 一個學生可以選擇多門課,一門課也有多名學生。

1.一對多關系處理:

       通過學生和班級問題了解一對多:

技術分享

       設計數據庫表:只需在 學生表 中多添加一個班級號的ID;

注:在數據庫中創建表時,還是通過添加主外鍵約束,避免刪除數據時造成數據混亂

 

2.多對多關系處理:

    通過學生選課了解多對多問題的處理:

技術分享

 

       在多對多中在一個表中添加一個字段就行不通了,所以處理多對多表問題時,就要考慮建立關系表了

例:

 學生表:技術分享     課程表:技術分享   關系表:技術分享

 

注:所以對於多對多表,通過關系表就建立起了兩張表的聯系!多對多表時建立主外鍵后,要先刪除約束表內容再刪除主表內容

 

 

 

數據表結構設計,絕大部分情況下是有冗余的,沒有冗余的情況不太容易做到,即使做到了,那么開發的人肯定會死去活來的。因為這樣的原因,在實踐中很少用到超過3NF的范式

 

==================

http://skypegnu1.blog.51cto.com/8991766/1668871

一、關系的實現

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

 

一對多

    這里先講解一對多,因為這個關系最簡單。一對多和多對一是一回事,所以就不再提多對一這個詞。一對多的概念是一個對象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字段,指向班級表,並建立唯一約束呢?除了不滿足“每個班必然有一個班主任”這個業務約束外,其他都沒有問題。所以如果對於一對一的情況,如果那邊必須要求持有另一邊,則就在哪邊增加外鍵字段;如果沒有要求必須持有一個另一類實體的話,就哪邊添加外鍵列都行。

 

外鍵與索引

    外鍵:如果一個表中的若干個字段是來自另外若干個表的主鍵,則這若干個字段就是外鍵。外鍵並沒有強制一定來自其他另外的表,也可能來自本表的主鍵。含有外鍵的表通常叫做外建表,外鍵字段來自【參考】的那個表則叫做主鍵表

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

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

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

 

二、主鍵的設計

    在數據庫設計時,主要就是對實體和關系的設計,實體表現出來就是表,關系表現出來就是外鍵。而對於一個表,由兩部分組成:主鍵和屬性。主鍵的簡單定義就是表中為每一行數據的唯一標識。其實更准確的說法,每一行數據的唯一標識是候選鍵(Candidate Key),一個表中可以有很多個候選鍵,主鍵是候選鍵中的一個,主要用於更方便的檢索和管理數據。一個表中可以有多個候選鍵,但是只有一個主鍵。由於主鍵常常用於檢索數據,也用於表之間的關聯,所以主鍵的設計的好壞將會嚴重影響數據操作的性能。下面來介紹下主鍵設計的幾個考慮因素。

 

主鍵的數據類型

    最常見的主鍵數據類型是數字類型、固定長度的字符類型和GUID類型。通常情況下,RDBMS會在主鍵上建立聚集索引(SQL Server默認都這么做),由於我們使用B-Tree的數據結構來存儲索引數據,所以一般對主鍵有以下兩個要求:

  • 越短越好——越短在一個Page中存儲的節點越多,檢索速度就越快。

  • 順序增長——如果每一條插入的數據的主鍵都比前面的主鍵大,那么B-Tree上的節點也是順序增長的,不會造成頻繁的B-Tree分割。

越短越好是為了查詢的速度快,順序增長是為了插入速度快。

 

有了這兩個要求,我們再來分析下各個數據類型:

數字類型:根據數據量決定是用Int16還是Int32或者Int64,能用Int32的就不需要使用Int64

字符類型:基本不滿足前面提到的2點要求,字符類型一般不會很短,而且也很可能不是順序增長的,所以不是特別推薦的主鍵類型。當然如果確實業務需求使用字符類型,那么也盡量使用char(XX)而不要使用varchar(XX),因為在RDBMS中,對於定長字符串和變成字符串的數據結構和處理是不一樣的,varchar的性能更差。

GUID類型:這個類型並不是所有數據庫都有對應的數據類型,SQL Server有uniqueidentifier,MySQL沒有。GUID類型在SQL Server中是16個字節,不算短,比4個字節的Int32長多了。在插入新數據時,GUID一般都是使用NewId()這樣的生成隨機GUID的方式生成的,所以也不是順序增長的,在插入速度上不會很快。

通過上面的比較,我們知道使用【數字類型】是更好的方式,那么我們為什么還會有人使用GUID和字符串來當主鍵呢?那是因為:

  • 相對於數字類型,字符類型更易讀易記,在檢索關聯的數據時,更方便直接

  • GUID的優勢是全球唯一,也就是說同樣的系統,如果部署了多套環境,那么里面的數據的主鍵仍然是唯一的,這樣有助於數據的集成。典型的例子就是一個系統在全國每個省份都部署一套,每個省份的數據各種錄入,互不干擾,然后再把每個省的數據集成起來為總部做分析。

最佳實踐:

  • 主鍵通常都是整數,不建議使用字符串當主鍵(如果主鍵是用於集群式服務,可以采用字符串類型)

  • 主鍵的值通常都不允許修改,除非本記錄被刪除

  • 主鍵的值通常不重用,意味着記錄被刪除后,該主鍵值不再使用。

  • 主鍵不要直接定義成【id】,而要加上前綴,定義成【表名id】或者【表名_id】

  • 要用代理主鍵,不要使用業務主鍵(自增id)

    • 任何一張表,強烈建議不要使用有業務含義的字段充當主鍵

    • 我們通常都是在表中單獨添加一個整型的編號充當主鍵字段

 

數據庫主鍵與業務主鍵

    前面說到一個表可能有很多個唯一標識的候選鍵,那么這么多候選鍵中,哪個應該拿來做主鍵呢?一種方案是再新建一個獨立的字段作為主鍵,該字段並沒有業務含義,只是一個自增列或者流水號,用於唯一標識每一行數據,這是數據庫主鍵。另外一種方案是選擇其中較短較常用的屬性作為主鍵,這是業務主鍵。個人建議是不要使用任何有業務含義的字段作主鍵,而是使用一個自增的(或者系統生成的)沒有實際業務意義的字段作為主鍵。為什么呢?主要是出於以下考慮:

  • 具有業務意義的字段很可能是用戶從系統錄入的,不要信任用戶的任何輸入,只要是用戶自己錄入的,那么就很有可能錄錯了,如果發現錄入錯誤,這個時候再對主鍵進行修改,將會涉及到大量關聯的外鍵表的修改,是很麻煩的一件事情比如在做人員表的時候,就不要使用員工號或者身份證號做主鍵。

  • 具有業務意義的字段雖然在當前階段是唯一的,是不變的,但是並不能保證隨着公司政策變動、業務調整等原因,導致該業務字段需要修改,以滿足新的業務要求,這個時候要修改主鍵也是很麻煩的事情。比如部門表,我們以部門Code作為主鍵,但是后來部門變動,Code修改,則系統部門表的主鍵也得更改。

  • 還有一個原因是業務主鍵在數據錄入的時候不一定是明確知道的,有時我們會在不知道業務主鍵的情況下,就錄入其他相關信息,這個時候,如果使用業務主鍵做數據庫的主鍵,那么數據將無法錄入。比如員工表把員工號作為主鍵,那么員工還沒有入職,沒有員工號的時候,HR需要先維護一些該預入職員工的信息是不可能的。

 

聯合主鍵

    聯合主鍵就是以多個字段來唯一標識每一行數據。前面已經說到主鍵應該越短越好,而且是建議是一個沒有意義的自增列,那么是不是就不會再需要聯合主鍵呢?答案是否定的,我們仍然可能會使用到聯合主鍵。聯合主鍵主要使用在多對多的關系時,中間表就需要使用聯合主鍵在簡單的多對多關系中,我們不需要為中間的關聯建立實體,所以中間表可能就只需要兩列,分別是兩個實體表的主鍵

 

主鍵值的生成

主鍵值的生成可以參考NHibernate的配置,概況下來主要有這么幾種生成方式:

  • 自增,這是SQL Server常用的主鍵生成方式,完全由數據庫管理主鍵的值。

  • Sequence對象,這是Oracle常用的主鍵生成方式,現在SQL Server已支持。主要是在數據庫中有一個Sequence對象,通過該對象生成主鍵。

  • GUID,這是用於GUID類型的主鍵,可以使用newid()這種數據庫提供的函數,或者使用程序生成Guid並賦值。

  • Hilo值,這是一種使用高低位算法生成的數字值的主鍵。該值由NHibernate程序內部生成。

  • 其他程序賦值,完全由程序根據自己的算法生成並賦值。

更詳細的主鍵生成,我們可以參見:http://www.cnblogs.com/chenkai/archive/2009/04/13/1434912.html

 

主鍵與索引

    在概念和作用上,主鍵與索引是完全兩個不同的東西,但是由於我們大部分情況下都是使用主鍵檢索數據,所以大部分數據庫的默認實現,在建立主鍵時會自動建立對應的索引。

 

以SQL Server為例,默認情況下,建立主鍵的列,就會建立聚集索引,但是實際上,我們可以在建立主鍵時不使用聚集索引。另外還有一個唯一約束(索引)的概念,該索引中的數據必須是唯一不能重復的,感覺和主鍵的意義一樣,但是還是有一點點區別。

  • 主鍵是只能由一個,而唯一約束(索引)在一個表中可以有多個。

  • 主鍵不能為空,而唯一約束(索引)是可以為空的。

 

主鍵表和外鍵表刪除問題?

    先刪除主鍵表還是外鍵表呢?

    先刪除外鍵表,在刪除主鍵表。如果先刪除主鍵表,會報錯,因為這會導致外鍵表中的數據引用失敗。這就是外鍵的作用:數據一致性

 

 

===========================

http://13145200724.blog.51cto.com/6263780/1370753

 

 

在數據庫中,如果兩個表的之間的關系為,多對多的關系,如:“學生表和課程表”,一個學生的可以選多門課,

一門課也可以被多門學習選;根據數據庫的設計原則,應當形成第三張關聯表

 

 

 

步驟1:創建三張數據表Student ,Course,Stu_Cour

 

/**學生表*/
CREATE TABLE student (
stu_id INT AUTO_INCREMENT,
NAME VARCHAR(30),
age INT ,
class VARCHAR(50),
address VARCHAR(100),
PRIMARY KEY(stu_id)
)

/*學生課程表*/
CREATE TABLE Course(
cour_id INT AUTO_INCREMENT,
NAME VARCHAR(50),
CODE VARCHAR(30),
PRIMARY KEY(cour_id)
)

/**學生課程關聯表*/
CREATE TABLE Stu_Cour(
sc_id INT AUTO_INCREMENT,
stu_id INT ,
cour_id INT,
PRIMARY KEY(sc_id)
)

  

 

第二步:為Stu_Cour表添加外鍵

 

 
/*添加外鍵約束*/
ALTER TABLE Stu_Cour ADD CONSTRAINT stu_FK1 FOREIGN KEY(stu_id) REFERENCES student(stu_id)
ALTER TABLE Stu_Cour ADD CONSTRAINT cour_FK2 FOREIGN KEY(cour_id) REFERENCES Course(cour_id)

 


免責聲明!

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



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