一、設計數據庫的必要性
- 1. 為什么要設計數據庫
當數據庫比較復雜(如數據量大,表較多,業務關系復雜)時,我們需要先設計數據庫,
因為:
- 良好的數據庫設計:
- 節省數據的存儲空間
- 能夠保證數據的完整性
- 方便進行數據庫應用系統的開
- 糟糕的數據庫設計:
- 數據冗余、存儲空間浪費
- 數據更新和插入的異常
二、軟件項目開發周期中的數據庫開發
- 1. 數據庫生命周期
數據庫的生命周期主要分為四個階段:
- 1. 需求分析階段:(此階段在軟件項目開發周期中的需求分析階段進行)這個階段主要是收集並分析用戶的業務和數據處理需求
- 收集信息(我們需要與數據的創造者和使用者進行訪談。對訪談獲得的信息進行整理、分析,並撰寫正式的需求文檔。需求文檔中需包含:需要處理的數據;數據的自然關系;數據庫實現的硬件環境、軟件平台等;)
- 標識對象
- 標識每個對象的屬性
- 標識對象之間的關系
- 2. 邏輯設計階段:(此階段在軟件項目開發周期中的概要設計和詳細設計階段進行)
使用ER或UML建模技術,創建概念數據模型圖,展示所有數據以及數據間關系。最終概念數據模型必須被轉化為范式化的表。
- a. 繪制E-R圖
- b. 將E-R圖轉換為表格
- c. 應用三大范式規范化表格
- 3. 物理設計階段:
根據特定數據庫管理系統所提供的多種存儲結構和存取方法等依賴於具體計算機結構的各項物理設計措施,對具體的應用任務選定最合適的物理存儲結構(包括文件類型、索引結構和數據的存放次序與位邏輯等)、存取方法和存取路徑等。這一步設計的結果就是所謂“物理數據庫”。
- a. 數據庫物理設計的目標是盡可能優化性能。
- b. 物理設計階段,表結構可能需要進行重構來滿足性能上的需求,這被稱為反范式化。
- c. 反范式化的步驟包括:
- I. 辨別關鍵性流程,如頻繁運行、大容量、高優先級的處理操作
- II. 通過增加冗余來提高關鍵性流程的性能
- III. 評估所造成的代價(對查詢、修改、存儲的影響)和可能損失的數據一致性
- d. 實現維護階段:
- I. 當設計完成之后,使用數據庫管理系統(DBMS)中的數據定義語言(DDL)來創建數據結構。
- II. 數據庫創建完成后,應用程序或用戶可以使用數據操作語言(DML)來使用(查詢、修改等)該數據庫。
- III. 一旦數據庫開始運行,就需要對其性能進行監視。當數據庫性能無法滿足要求或用戶提出新的功能需求時,就需要對該數據庫進行再設計與修改。這形成了一個循環:監視 –> 再設計 –> 修改 –> 監視…。
三、數據庫設計實現步驟
- a. 需求分析階段
- I. 收集信息
與該系統有關人員進行交流、坐談,充分理解數據庫需要完成的任務
- b. 標識對象(實體-Entity)
標識數據庫要管理的關鍵對象或實體
- 3. 標識每個實體的屬性(Attribute)
- 4. 標識對象之間的關系(Relationship)
- 2. 邏輯設計階段
- 1. 繪制E-R圖
實體關系圖(Entity Relationship Diagram),是指提供了表示實體型、屬性和聯系的方法,用來描述現實世界的概念模型。
ER模型中的基本元素
基本的ER模型包含三類元素:實體、關系、屬性
元素說明:
- 1. 實體(Entities):實體是首要的數據對象,常用於表示一個人、地方、某樣事物或某個事件。一般名稱單詞的首字母大寫。
辨別強實體與弱實體:
- 在現實世界中,有時某些實體對於另一些實體有很強的依賴關系,即一個實體的存在必須以另一實體的存在為前提。前者就稱為“弱實體”,后者稱為“強實體”。比如在人事管理系統中,職工子女的信息就是以職工的存在為前提的,子女實體是弱實體,子女與職工的聯系是一種依賴聯系。
- 強實體內部有唯一的標識符。
- 弱實體(weak entities)的標識符來自於一個或多個其它強實體。弱實體用雙線長方形框表示,依賴於強實體而存在。
- 2. 關系(Relationships):關系表示一個或多個實體之間的聯系。關系依賴於實體,一般沒有物理概念上的存在。
關系最常用來表示實體之間,聯系可分為以下 3 種類型:
- 一對一聯系(1 ∶1) :例如,一個部門有一個經理,而每個經理只在一個部門任職,則部門與經理的聯系是一對一的。
- 一對多聯系(1 ∶N) :例如,部門與員工之間存在一對多的聯系“所屬”,即每個部門可以有多個員工,但是每個員工只能隸屬一個部門
- 多對多聯系(M ∶N) :例如,學生與課程間的聯系(“學 ”)是多對多的,即一個學生可以學多門課程,而每門課程可以有多個學生來學。聯系也可能有屬性。例如,學生“ 學” 某門課程所取得的成績,既不是學生的屬性也不是課程的屬性。由於“ 成績” 既依賴於某名特定的學生又依賴於某門特定的課程,所以它是學生與課程之間的聯系“ 學”的屬性。
關系的構圖是一個菱形,關系的名稱一般為動詞。
- 3. 屬性(Attributes):屬性為實體提供詳細的描述信息。一個特定實體的某個屬性被稱為屬性值。Employee實體的屬性可能有:emp-id, emp-name, emp-address, phone-no……。屬性一般以橢圓形表示,並與描述的實體連接。
屬性可被分為兩類:
- a. 標識符(identifiers):Identifiers可以唯一標識實體的一個實例(key),可以由多個屬性組成。ER圖中通過在屬性名下加上下划線來標識。
- b. 描述符(descriptors):多值屬性(multivalued attributes)用兩條線與實體連接,eg:hobbies屬性(一個人可能有多個hobby,如reading,movies…)。復合屬性(Complex attributes)本身還有其它屬性。
- 1. 繪制實體對象及關系
- 2. 確定表之間的關系,完成E-R圖
- 2. 將E-R圖轉換為表
- 具體做法
- 1. 實體類型的轉換
- a. 將每個實體類型轉換成一個關系模式。
- b. 實體的屬性即為關系模式的屬性。
- c. 實體標識符即為關系模式的主鍵。
標識每個表的主鍵列,需要注意的是:沒有主鍵的表添加ID編號列,它沒有實際含義,用於做主鍵或外鍵,例如用戶表中的“UID”列,版塊表中添加“SID”列,發貼表和跟貼表中的“TID”列
注意:《database system concepts》里面提到主鍵的定義是表中唯一的標識,“應該選擇從不變化或極少變化的屬性”。
否則,建議大家根據實際情況使用沒有意義的邏輯主鍵
在表之間建立主外鍵,體現實體之間的映射關系
- 實體間關系的轉換
- a. 對於二元聯系,按各種情況處理,如下面所示。
二元關系 |
ER圖 |
轉換成的關系 |
聯系的處理 |
主鍵 |
外鍵 |
1:1 |
(2個關系) 模式A 模式B |
(有兩種) 處理方式1:把模式B的主鍵,聯系的屬性加入模式A 處理方式2:把模式A的主鍵,聯系的屬性加入模式B |
(略) |
(依據聯系的處理方式) 方式1: 模式B的主鍵為模式A外鍵 方式2:表A的主鍵為表B的外鍵 |
|
1:N |
(2個關系) 模式A 模式B |
把模式A的主鍵,聯系的屬性加入模式B |
(略) |
模式A的主鍵為模式B的外鍵 |
|
M:N |
(3個關系) 模式A 模式B 模式A-B |
聯系類型轉換成關系模式A-B; 模式A-B的屬性: (a)聯系的屬性 (b)兩端實體類型的主鍵 |
兩端實體類型的主鍵一起構成模式A-B主鍵 |
兩端實體類型的主鍵分別為模式A-B的外鍵 |
轉換步驟:
(1)把三個實體類型轉換成三個模式:
①系(系編號,系名,電話)
②教師(教工號,姓名,性別,職稱)
③課程(課程號,課程名,學分)
(2)對於1:1聯系“主管”,可以在“系”模式中加入教工號(教工號為外鍵)。
①系(系編號,系名,電話,主管人的教工號)
對於1:N聯系“聘用”,可以在“教師”模式中加入系編號和聘期兩個屬性(系編號為外鍵)
②教師(教工號,姓名,性別,職稱,系編號,聘期)
(3)第三步:對於M:N聯系“任教”,則生成一個新的關系模式:
①任教(教工號,課程號,教材)
(4)第四步:轉換成以下模式:
關系模型 |
主鍵 |
外鍵 |
系(系編號,系名,電話,主管人的教工號) |
系號 |
主管人教工號 |
教師(教工號,姓名,性別,職稱,系編號,聘期) |
教工號 |
系編號 |
課程(課程號,課程名,學分) |
課程號 |
|
任教(教工號,課程號,學分) |
教工號,課程號 |
教工號,課程號 |
- b. 一元聯系類型的轉換
和二元聯系類型的轉換類似。
職工之間存在上下級聯系,即1:N聯系
可以轉換成以下模式:
關系模型 |
主鍵 |
職工(工號,姓名,年齡,性別,經理工號) |
工號 |
工廠的零件之間存在着組合關系(M:N聯系)
①零件(零件號,零件名,規格)
②組成(零件號,子零件號,數量)
可以轉換成以下模式:
關系模型 |
主鍵 |
零件(零件號,零件名,規格) |
零件號 |
組成(零件號,子零件號,數量) |
零件號,子零件號 |
- c. 三元聯系類型轉換
(1)若實體間聯系是1:1:1,可以在三個實體類型轉換成的三個關系模式中任意一個關系模式的屬性中加入另兩個關系模式的鍵(作為外鍵)和聯系類型的屬性。
(2)若實體間聯系是1:1:N,則在N端實體類型轉換成的關系模式中加入兩個1端實體類型的鍵(作為外鍵)和聯系類型的屬性。
(3)若實體間聯系是1:M:N,則將聯系類型也轉換成關系模式,其屬性為M端和N端實體類型的鍵(作為外鍵)加上聯系類型的屬性,而鍵為M端和N端實體鍵的組合。
(4)若實體間聯系是M:N:P,則將聯系類型也轉換成關系模式,其屬性為三端實體類型的鍵(作為外鍵)加上聯系類型的屬性,而鍵為三端實體鍵的組合。
三元聯系的ER圖
1:1:1關系 技術員在項目中使用手冊的關系
說明:
- 一名技術主管對於每一個項目使用一本說明手冊
- 一本說明手冊對於每一個項目屬於一名技術主管
- 一個項目有一個技術主管一本說明書
可以轉換成以下模式:
關系模型 |
主鍵 |
Technician(TechnicianID,TechnicianName) |
TechnicianID |
Notebook(NotebookID,NotebookName) |
NotebookID |
Project(ProjectID,ProjectName,NotebookID,TechnicianID) |
ProjectID |
1:N:M 經理管理項目與工程師的關系
說明:
- 一名經理手下的一名工程師可能參與多個項目
- 一名經理管理的一個項目可能會有多名工程師
- 做某一個項目的一名工程師只會有一名經理
可以轉換成以下模式:
關系模型 |
主鍵 |
Engineer(EngineerID,EngineerName) |
EngineerID |
Manager(ManagerID,ManagerName) |
ManagerID |
Project(ProjectID,ProjectName) |
ProjectID |
Manages(EngineerID,ProjectID,ManagerID) |
EngineerID,ProjectID |
可以轉換成以下模式:
關系模型 |
主鍵 |
倉庫(倉庫號,倉庫名名,地址) |
倉庫號 |
商店(商店號,商店名) |
商店號 |
商品(商品號,商品名) |
商品號 |
進貨(商店號,商品號,倉庫號,日期,數量) |
商店號,商品號,倉庫號 |
- 規范化關系模型表格
僅有好的RDBMS並不足以避免數據冗余,必須在數據庫的設計中創建好的表結構
范式是具有最小冗余的表結構。這些范式是:
- a. 第一范式(1st NF -First Normal Fromate)
- b. 第二范式(2nd NF-Second Normal Fromate)
- c. 第三范式(3rd NF- Third Normal Fromate)
- 1. 第一范式 (lNF)
|
|
|
- 2. 第二范式(2NF)
例如:
表關系雖滿足lNF,但不滿足2NF,
原因:因為它的非主屬性不完全依賴於由教師代碼和課題代碼組成的主關鍵字。
姓名,職稱 部分依賴於 教師代碼 研究課題名稱 部分依賴於 研究課題號
導致問題: 這種關系會引起數據冗余 更新異常,當要插入新的研究課題數據時,往往缺少相應的教師代碼,以致無法插入 當刪除某位教師的信息時,常會引起丟失有關研究課題信息。
解決辦法: 將一個非2NF的關系模式分解為多個2NF的關系模式。 |
|
|
|
||
|
表被分解為如下三個關系: |
|
|||
|
·教師表:教師代碼、姓名、職稱; ·課題表:研究課題號、研究課題名; ·教師與課題表:教師代碼、研究課題號。 |
|
|||
|
這些關系都符合2NF要求。 |
|
|||
- 3. 第三范式(3NF)
如果一個關系滿足2NF,並且除了主鍵以外的其他列都不傳遞依賴於主鍵列,則滿足第三范式(3NF)
例如:
表產品關系屬第二范式,但不是第三范式。
原因:由於生產廠名依賴於產品代碼 (產品代碼惟一確定該產品的生產廠家),生產廠地址又依賴於廠名,因而,生產廠地址傳遞依賴於產品代碼。
導致問題:
存在數據冗余
更新異常問題
當刪除一個產品記錄時,可能造成所連帶的唯一一條生產廠商信息連帶刪除掉,造成數據丟失。
解決辦法:
消除傳遞依賴關系的辦法,是將原關系分解: |
|
產品表:產品代碼、產品名、生產廠名; 生產廠表 :生產廠名、生產廠地址。
3NF消除了插入、刪除異常及數據冗余、修改復雜等問題,已經是比較規范的關系
|
|
- 4. 規范化和性能
范式可以避免數據冗余,減少數據庫的空間,減輕維護數據完整性的麻煩,但是操作難,因為需要聯系多個表才能得到所需要數據,而且越高范式性能就會越差。要權衡是否使用更高范式是比較麻煩。
為滿足某種商業目標,數據庫性能比規范化數據庫更重要
通過在給定的表中添加額外的字段,以大量減少需要從中搜索信息所需的時間
通過在給定的表中插入計算列(如成績總分),以方便查詢
進行規范化的同時,還需要綜合考慮數據庫的性能。
- 5. 案例
假設某建築公司要設計一個數據庫。公司的業務規
則概括說明如下:
- 公司承擔多個工程項目,每一項工程有:工程號、工程名稱、施工人員等
- 公司有多名職工,每一名職工有:職工號、姓名、性別、職務(工程師、技術員)等
- 公司按照工時和小時工資率支付工資,小時工資率由職工的職務決定(例如,技術員的小時工資率與工程師不同)
- 公司定期制定一個工資報表和項目工時表,如圖
工資報表
工程號 |
工程名稱 |
職工號 |
姓名 |
職務 |
小時工資率 |
工時 |
實發工資 |
A1 |
花園大廈 |
1001 |
齊光明 |
工程師 |
65 |
13 |
845.00 |
|
|
1002 |
李思岐 |
技術員 |
60 |
16 |
960.00 |
|
|
1004 |
葛宇宏 |
律師 |
60 |
19 |
1140.00 |
|
|
|
小計 |
|
|
|
2945.00 |
A2 |
立交橋 |
1001 |
齊光明 |
工程師 |
65 |
15 |
975.00 |
|
|
1003 |
鞠明亮 |
工人 |
55 |
17 |
935.00 |
|
|
|
小計 |
|
|
|
1910.00 |
A3 |
臨江飯店 |
1002 |
李思岐 |
技術員 |
60 |
18 |
1080.00 |
|
|
1004 |
葛宇洪 |
技術員 |
60 |
14 |
840.00 |
|
|
|
小計 |
|
|
|
1920.00 |
項目工時表
工程號 |
工程名稱 |
職工號 |
姓名 |
職務 |
小時工資率 |
工時 |
A1 |
花園大廈 |
1001 |
齊光明 |
工程師 |
65 |
13 |
A1 |
花園大廈 |
1002 |
李思岐 |
技術員 |
60 |
16 |
A1 |
花園大廈 |
1001 |
齊光明 |
工程師 |
65 |
13 |
A1 |
花園大廈 |
1003 |
鞠明亮 |
工人 |
55 |
17 |
A3 |
臨江飯店 |
1002 |
李思岐 |
技術員 |
60 |
18 |
A3 |
臨江飯店 |
1004 |
葛宇洪 |
技術員 |
60 |
14 |
表中包含大量的冗余,可能會導致數據異常:
- 更新異常------------ 例如,修改職工號=1001的職務,則必須修改所有職工號=1001的行
- 添加異常------------ 若要增加一個新的職工時,首先必須給這名職工分配一個工程。或者為了添加一名新職工的數據,先給這名職工分配一個虛擬的工程。(因為主關鍵字不能為空)
- 刪除異常------------ 例如,1001號職工要辭職,則必須刪除所有職工號=1001的數據行。這樣的刪除操作,很可能丟失了其它有用的數據
采用這種方法設計表的結構,雖然很容易產生工資報表,但是每當一名職工分配一個工程時,都要重復輸入大量的數據。這種重復的輸入操作,很可能導致數據的不一致性。
應用規范化設計
一張表描述了多件事情,如圖
三、總結
- 數據庫設計必要性
- 數據庫在軟件開發中的生命周期及各階段任務
- 數據庫設計步驟
- 1. 在需求分析階段,設計數據庫的一般步驟為:
- 1. 收集信息
- 2. 標識對象
- 3. 標識每個對象的屬性
- 4. 標識對象之間的關系
- 2. 在概要設計階段和詳細設計階段,設計數據庫的步驟為:
- 1. 繪制E-R圖
- 2. 將E-R圖轉換為表格
- 3. 應用三大范式規范化表格
- 3. 為了設計結構良好的數據庫,需要遵守一些專門的規則,稱為數據庫的設計范式 。
- 1. 第一范式(1NF)的目標:確保每列的原子性。
- 2. 第二范式(2NF)的目標:確保表中的每列,都和主鍵相關
- 3. 第三范式(3NF)的目標:確保每列都和主鍵列直接相關,而不是間接相關
- 4. 規范化和性能