引言數據庫設計是信息系統設計的基礎,一個好的數據庫設計在滿足了軟件需求之外,還要易維護、易擴充等等要求。當然,對專家們反復強調的數據的一致性、冗余性、訪問效率等問題的解決,很大程度上取決于數據庫設計者的經驗和專業水平。但這不妨礙我們根據過去的經驗,從實用的角度給出數據庫設計所要要考慮的問題并盡可能給出相應的解決方案,從而給信息系統的數據庫設計者一些有益的啟示。(注:這里的數據庫設計主要指數據庫中表和視圖的schema設計,不涉足數據庫系統中其他方面的設計)那么怎樣才算是一個好的數據庫設計呢?以下給出一個一般性的標準。
一、一個好的數據庫設計首先要滿足用戶的需求
所有信息系統最后都將提交給最終用戶使用,對于這一點,相信大家都已經達成共識。但是準確地把握用戶的需求是很難的,雖然各方面的專家已經從不同方面給出了解決方案,但是用戶需求仍然是軟件工程中最不確定的因素之一。
二、一個好的數據庫設計要便于維護和擴充
為了應對用戶需求的修改和添加,也為了滿足各種不同的軟硬件環境下系統的使用,大部分信息系統都不得不在其生命期中進行升級和調整。在這些升級、調整中,又有相當部分會涉及到數據庫設計的修改,因此,數據庫設計最好從一開始就能在易維護、可擴充的角度多加斟酌。
1、不要為各種編號字段的設定固定的意義
而是最好通過對照表來建立這種編號和意義的對照關系。舉例來說,很多設計者習慣給部門信息給出固定的編號,這種設計有個致命的缺陷:那就是由于這種對照關系既然不體現在數據庫中,就必然要用業務邏輯來進行解釋,這樣一來,一有新的調整就不得不更新業務邏輯代碼,也就非常容易不一致的錯誤。
2、枚舉信息要體現在相應在對照表中
而不是體現在使用該信息的表中的值字段,這樣做的好處是當用戶希望用該枚舉信息作為查詢條件的時候,通過參照表的方式可以很容易的建立這些信息,另外也避免了當多個表格中都含有該枚舉信息有可能引起的不一致。
3、用關聯表建立表和表之間的多對多關系
而不要用一個字段解析的方式進行,舉例來說,為了描述用戶(UserInfo)和角色(RoleInfo)之間的關聯關系,我們要建立對照表UserInfo_RoleInfo,而不要試圖在用戶表中建立一個較長的字段,如Roles(用RoleID1;RoleID2…的形式構成)來代替,因為這樣一來字段解釋需要在業務代碼相應的解析代碼,二來由于Roles定長,無法滿足用戶角色的擴充。
三、一個好的數據庫設計要具有“可讀性”
如同編程書籍中反復強調的程序員一定要在代碼的可讀性方面下功夫一樣,考慮到信息系統將來的升級和維護可能要要由另外一批人來進行,因此數據庫設計必然也要具有可理解性。對此,我們參照提高代碼可讀性的常用方法,給出一些建議:
1、用設計文檔來提高數據庫設計的可讀性
這點基本對應于“可讀性”代碼里面的注釋。在一個合格的數據庫設計文檔中必須給出數據庫中的每個表、每個字段、表間的關聯關系以及各種約束的意義以及由來,從而有可能讓開發者根據用戶需求和設計文檔就能理解正確數據庫的設計。
2、給表和視圖起一個有意義的名字
這點對應于coding規范中的變量和函數的命名,很顯然,CustomerInfo的名字很容易聯想到該表中含有客戶信息,而把它命名為Table0001只能讓人感到費解外。另外,如果DBMS提供表和視圖名的大小寫支持,該名稱最好由每個構成單詞(首字母大寫)拼接而成。
3、用前綴給出表和視圖內容之外的其他信息
如給參照表Ref_前綴,這樣就可以讓業務邏輯實現人員根據表的名字知道他所要操作的是不是張參照表,從而幫助他更快地理解詳細設計,并有可能及早發現里面的錯誤。同樣,給所有視圖加上V_前綴,就可以讓業務邏輯編程者很容易地知道他現在面臨的是一個表還是視圖,從而避免了對視圖進行更新操作這種低級的錯誤。
4、給每一個字段起一個有意義的名字
如給CustomerInfo表中的電子郵件字段起名EMail讓人很容易明白它的準確含義,而Field05則讓人不知所云。基于同樣的道理,數據庫設計中也不能給字段起一個張冠李戴的名字。
5、字段命名要考慮上下文
舉例來說,在UserInfo表中,用UserName來表示用戶名字段就不如Name來的更加合適。這種情況畫蛇添足的情況在對照表的設計中體現得尤為明顯,如把部門對照表(Ref_Department)中的部門ID字段命名為DepartmentID,把部門名稱字段命名為DepartmentName等等。
6、視圖的設計不要牽扯到其他視圖
與代碼設計中函數調用最好不要嵌套過多層次相對應,為了便于數據庫設計的閱讀人能夠很好地理解設計,視圖最好直接建立在表上。
7、同一表中的記錄最好不要相互引用
這種引用關系不僅讓數據庫設計的閱讀人云里霧里,也不便于業務邏輯代碼的編寫。
8、關聯表的命名用關聯的表名中間加下劃線連接構成
如學生(StudentInfo)和課程(CourseInfo)的關聯表起名StudentInfo_CourseInfo。
四、一個好的數據庫設計能夠滿足空間和效率的要求
對于一個信息系統來說,在實現用戶需求的基礎之上,保證一個較低的空間占用以及短的響應時間都是理智的客戶所愿意看到的。那么在這一方面,數據庫設計又要做些什么工作呢?
1、使用varchar而不要使用char字段
對于不定長信息如用戶的簡介信息,varchar的使用可以減少近一半的空間占用。當然這點不能一概而論,如用相應長度的char存儲定長文本數據就比varchar來的合適。
2、不要使用BLOB字段存放“大數據”
BLOB字段誠如其名,本身是為存儲二進制大數據而出現的,同樣的道理也適用于某些DBMS所引入的TEXT字段。因為對于一般信息系統而言,最長的字段往往是一些描述文本信息,而DBMS對char/varchar的長度基本能滿足這種需求。因此積極建議設計者對一些貌似很長的文本的最大允許長度進行確認,在此基礎上參照DBMS中的開發手冊來決定是否采用大字段。
3、不要使用設計器缺省的字段長度
這種做法一方面縱容了設計者對用戶需求的一知半解以及對設計敷衍了事的不良習慣,另外一方面也在數據的存儲上浪費了不少的空間,因為使用缺省字段長度的情況往往發生在字段上。
4、不要輕易使用unicode文本字段
DBMS對unicode的支持在幫助產品國際化的同時,也在一定程度上帶來空間上的浪費,尤其是在當要存儲的文本中的基本都是ASCII字符的情況下,這種浪費尤為明顯。因此,建議設計者在選擇unicode的理由,一定是出于國際化的考慮,而不是其他。因為大多數的大字符集和ASCII字符并存情況下所要碰到的問題基本上都已經由DBMS提供商解決。
5、使用預計算表來提高響應速度
跟數據倉庫里面的某些思路相似,當業務邏輯中需要用倒根據歷史信息得來的統計數據時,最好由獨立于系統的預計算模塊或相應的DW工具定期完成這些統計數據的預計算。
五、一個好的數據庫設計可以簡化業務邏輯的設計
所有的數據庫設計都不是孤立的,它通過相應的業務邏輯實現(三層結構中還有表現層)來形成最終的產品,因此一個好的數據庫設計應該能夠幫助降低業務邏輯的編寫難度,最起碼不要給業務邏輯的設計、編碼帶來額外工作。
1、所有允許為空的字段必須是基于用戶需求,而不是出于設計上方便的考慮。這樣帶來的好處是讓詳細設計中的某些錯誤和疏漏(如在設計中沒有考慮對非空字段的內容檢查)在編碼和單元測試階段就被發現,從而避免了進一步擴散,有助于提高軟件的質量。
2、不要業務邏輯代碼實現唯一性約束
對數據庫表中的某些字段(或者多個字段的組合)的唯一性約束應該盡可能地加到數據庫端。因為這種約束工作交給業務邏輯中去實現代價高昂而且不可靠。
3、關聯約束一定要建立在數據庫端
分析出設計中所涉及的主外鍵引用關系并體現在數據庫設計中。這一條出于兩點考慮:降低業務邏輯的編寫難度和數據關聯性約束的要求。