轉自:http://blog.csdn.net/ccat/archive/2009/05/14/4180765.aspx
幾乎每一個新人在初學關系型數據庫設計的時候,都會接觸到關系范式。但是,我還是見到了大量很離譜的設計。客觀的說,背下關系范式,離一個合格的數據庫設 計師還差很遠。設計工作總是在理想與現實之,規范與工藝之間妥協。建筑如是,造船如是,操作系統設計如是,數據庫設計亦如是。
是的,你記得范式,你還記得反范式建議。你知道范式減少冗余,提高一致性;你還知道反范式可以方便編程。不幸的是,最終的結果總是遵守范式的做法使自己的應用層代碼混亂,而反范式的企圖使得數據庫也陷入混亂。
這是誰的錯?
不必太自責,設計工作是一個經驗的積累過程。沒有人天生就會做設計。天才與勤奮,是乘法關系。并不是你笨,只是天才對面的那個系數還不夠大而已。
以下的一些經驗,或許在你讀完關系范式以后,可以抽空看一看 。世上沒有魔法,讀完這篇文章,并不會立即讓你擁有多年設計經驗。但是,這些在設計工作中積累的經驗教訓,應該可以幫助你少走一些彎路。
關于范式
關系范式并不邪惡,也不要把它想得太神秘,如果書本上的定義不能讓你很快理解,不妨試著回答以下的問題:
字段還可以再分嗎?分成兩個或更多的字段以后,還能不能表達完整的含義?
字段的值是不是有限的幾個離散的狀態?
兩個或若干個字段,能不能提取出來建立為一個數據字典?
如果表中某個字段依賴其他表,被依賴的字段是不是唯一的(最好是主鍵)?
查詢中是否會出現超過兩個表的Join?
將數據庫設計與系統設計結合起來
數據庫設計并不是一個孤立的過程,整個軟件生命期中,各方面的工作應該有機結合。這方面我覺得ACCP過去的教材講得還不錯,至少思路是對的:
在做需求分析的時候,做Use Case。 此時可以分析出應用層的功能接口,對于數據庫的實體分類可以有一個大概的劃定。例如,這個項目會需要一個工作流,這個項目會需要一個訂單系統,或者一個文檔庫,等等。通常,每個子系統可以對應一個
在做概要設計的時候,出類關系和ER簡圖。 通常來說,此時不能確定所有的字段,但是會有哪些表,有哪些主外鍵依賴,有哪些地方應該需要存儲過程和觸發器的輔助,等等。
詳細設計時盡可能將數據庫結構完全固定。 盡管現代開發工具不斷提升XP能力,重構越來越簡單。數據庫的重構仍然是一件牽一發而動全身的事情,畢竟數據庫是信息存儲的根本。大廈樓頂加個小花園容易,把地基下面的承重柱子拔出來換兩根試試?
重視SQL
近年來ORM發展很快,幾乎每個框架都要提供這個功能,以至于會有些菜鳥認為“ORM”會淘汰SQL語言。
這是一塊試金石,如果你有這樣的感覺,應該考慮認真評估一下自己在這個領域是不是太菜了。
SQL不是一種編程語言這么簡單,SQL代表的是一種與應用開發語言完全不同的思想。面向集合,過程無關,著眼于規則定義。可以說,SQL是FP High Order計算的最成功應用,也可以說,SQL是一種靜態強類型的MapReduce語言。
看,換上時髦的名詞,會不會讓你覺得它上等起來了?
在應用層語言慘烈競爭的同時,SQL語言壓倒了同時代出現的其他關系型數據庫操作語言,在這個擁有巨大利潤的領域占據了絕對統治地位。即使桀驁不馴的 Postgres,也在1995年變身為PostgrSQL。這一過程,并非像VC淘汰BC那么多盤外招,而是長時間爭議與選擇的結果。
對于信息操作規則定義,SQL幾乎是最好的表達方式。接近自然語言,高度可讀,并且非常利于優化。
打個比方,一個基于過程語言的上帝,這樣說:
* 構造一個光源對象
* 構造一個能源對象
* 調用光源對象方法,設置能源
* 調用光源對象的發光方法,傳入照明范圍內的對象列表
基于SQL的上帝說,要有光。
當然,在這位老兄背后,要有打雜的小弟去完成插電點燈的事情,但是作為上帝,什么活都自己做了,要天使干什么?
看看那些應用層語言的list comprehensions(列表推導式)。不止一次我想要為Python實現一個基于存儲層的列表推導式實現,都可恥的失敗了。
當然,我承認這跟跟人能力有關,我不是Gudio。
看看LINQ,不管如何吹噓,它就是一個抽象出I/O的SQL。我見過一些人激烈的貶低SQL,抬高ORM,同時又對LINQ頂禮膜拜,這可真夠分裂的。
ORM對應用層編程效率的提升是客觀的,無需回避。但是隨著你數據操作越來越精細和復雜,就越來越需要通過規則定義來抽象High Order I/O過程。當你轉了一圈兒回來,會發現自己又在寫SQL。
想想Hibernate的HQL,想想C#的LINQ。
計算機不會變魔術。想讓它做事更聰明,就需要你這個馭者更加聰明才行。
好的工具和方法可以給你帶來更高的能力系數,但是記住,一個乘法計算,僅有一頭大是不夠的。
不懂SQL的人,是不能駕馭好ORM的。
與ORM做朋友
ORM對于開發工作,無疑是有好處的。我的朋友沈葳說,人腦能組織和分析的事務是有限的,所以代碼越短,越有利于提高代碼質量。從這個角度講,ORM是非常重要的開發工具,其意義不亞于C API 函數集到GUI 框架的進步。
要想讓ORM充分發揮威力,有時候需要從數據庫設計時就做出一定妥協。
例如,你往往會需要加入自增標識列,會放棄一些精巧但是不利于ORM訪問的依賴設定,甚至要放棄一些漂亮的命名(它們在應用層語言中是保留字,但是你用的ORM不懂如何規避)。
但是,這往往是必要的。就像建筑師向氣候和建筑材料妥協一樣。
在ORM默認的自增字段外,也許你還需要基于業務規則的唯一約束,那么額外加索引。
好的ORM會幫助你方便的查詢數據字典,生成對象映射,跟蹤數據變更,提供數據完整性的應用層檢查,構造兩階段提交事務,減少不必要的I/O。
同樣,不懂得運用ORM,也可能會破壞數據完整性,降低數據訪問速度,甚至造成數據庫死鎖。作為項目開發人員,應該將ORM視為朋友而不是負擔。
合理分層
過去,流行使用復雜的數據庫設計,將業務規則存儲于數據庫的存儲過程。現在,又流行拋棄數據層的一切約束,所有的規則都放在應用層。
這兩者都不合理,除了應用需求的影響,前者與Oracle的廣告部宣傳有關,后者與MySQL陣營的鼓動有關。背后都有一些不合理的力量推動。
每一層應該保證自己的完整性,這才是分層的意義。那么,在數據庫層,應該保證數據的完整性。
數據庫備份出來,再恢復進去,應該可以得到所有的業務信息。
直接向數據庫導入數據,應該可以有完整的數據規則保護。
數據庫里保存的,不僅僅是表和記錄,應該是完整的持久性信息。
從這個角度講,配置文件和應用層代碼中不應該有任何業務數據定義,這些信息都應該是數據字典表。如果出現了這種配置文件,大多數情況下都是愚蠢的錯誤。
實際上,包括Web網站常見的附件上傳,都應該保存在數據庫中。
獨立的I/O文件存儲、包括將外鍵約束轉移到應用層,往往是因為對性能的妥協。以及,這里面確實存在MySQL陣營在推廣過程中的一些不道德的宣傳。
有效利用數據庫功能,可以提高應用層的開發速度,簡化代碼結構,使得數據存儲更安全。這通常仰賴與設計人員的經驗,根據項目的具體需求進行調整。
基于這個原則,合理利用數據庫功能,編寫存儲過程,觸發器,調校索引,都是必要的。
我敢打賭,隨著MySQL實現越來越多的功能,它的宣傳材料上會越來越多的出現以前被MySQL所摒棄的復雜設計理念,并且宣稱這是MySQL所獨創或一貫倡導的。
收集整理常見的模式
在設計模式提出這么多年,在關系型數據庫問世如此之久后,我很驚訝的一件事就是數據庫設計模式仍然是一個相當冷門的領域。實際上,關系數據庫的模式也有很多 可循之規。例如用戶信息(HR或CRM)、工作流,權限管理(如RBAC),訂單等等,都有相當成熟的行業經驗和時間,往往只要修改一些字段名,或者在關 鍵架構的基礎上加以擴展,就可以很好的用于實踐。
每一個有志于成為高水平設計人員的開發者,都應該積極的收集自己體會到的數據庫設計模式,積極的與同行交流。
這方面,Oracle的示例Schema,Postgres的示例數據庫項目(在Soureforge上可以找到),都是很好的例子。相對來說,微軟在MSSQL和Access中提供的示例庫更為輕量和簡單,也是作為入門的不錯借鑒。