在博客園上看到了一篇關于數據庫范式的文章《數據庫設計中的五個范式》:
第三范式規則查找以消除沒有直接依賴于第一范式和第二范式形成的表的主鍵的屬性。我們為沒有與表的主鍵關聯的所有信息建立了一張新表。每張新表保存了來自源表的信息和它們所依賴的主鍵。
關于第三范式的思想,我想有很多朋友都熟悉,在數據庫設計時,也是我們盡可能采用的范式之一,第三范式的出發點是什么?就是盡可能的減小“數據冗余”、并也能得到“數據”的整潔性,提高維護性,不容懷疑,第三范式是我們努力、必須要去遵從的。
然而,有很多朋友把第三范式作為“不死的法寶”,但其實在實際的應用中,我們還是要從不同的業務出發,要合理的應用“第三范式”。下面我也就簡單的舉個例子:
一張訂單會關聯很多的基礎資料,如:客戶,付款條款,貨運方式等,這些信息是有專門表進行維護的,在下訂單時也是用下拉框選擇的,在保存訂單信息時,按照“第三范式”的要求,那應該只保存對應的主鍵值就OK了。因為這樣可以避免數據冗余,但對我來說,我不會這樣做,我會把客戶的名稱、聯系電話、付款條款名稱等訂單上要求記錄的信息直接COPY到訂單的表中。
這樣看來,我們違背了“第三范式”,是的,但在這里,我們違背“第三范式”也是有理由的:
1我不想在訂單下達完以后,刪除了某條付款條款,導致這些訂單無法知道“真實的付款條款”了,這肯定不合理。
2我也不想,因為下了這張訂單了,而“嚴格控制”付款條款的“刪除”功能,這也不合理,憑啥不能刪除了?下個月這個“條款”確實永遠不會采用了。
3我也不想,付款條款修改后,導致以前所有采用此付款條款的訂單都變成新的條款,那在系統中的訂單如何與手頭的紙張訂單再對應,這肯定也不合理。
所以,我的設計原則是,對于這種訂單我們應該采用“隔離”的方式來對待,讓基礎數據COPY到訂單中,這當然會違背所謂的“第三范式”,但這也是實際的需要啊。理論與實際是有差別的。
訂單--這種在現實中以實物的方式存在,實物具有與基礎數據的參考性,而不是關聯性,基礎數據只能是作為訂單這個實物的一個“參考”,而不是“關聯”,這可以稱為“獨立性”;再者,訂單具有一定的歷史性,因為是實物,在實際的過程中,是即時生成的,那么在生成的當時去參考了基礎數據,訂單就在當時被確定,確對不能因為基礎數據的修改而導致訂單被“無辜變性”了,這也就是訂單的“歷史性”,當以后翻閱這些紙張訂單時也能對應上系統里的訂單。
這是我所理解的最典型的例子,在實際的系統設計中,我們應該多思考一下,是不是要采用“第三范式”,不要再盲目追捧了。
以上純屬我個人意見,僅供參考,歡迎大家討論。
Feedback
#1樓 回復 引用 查看
2005-05-08 14:23 by
#2樓 回復 引用 查看
2005-05-08 14:25 by 嘿嘿
#3樓 回復 引用 查看
2005-05-08 14:39 by
#4樓 回復 引用 查看
2005-05-08 14:56 by
#5樓 回復 引用 查看
2005-05-08 15:07 by
#6樓 [樓主] 回復 引用 查看
2005-05-08 15:21 by
寒楓天傷 :
我覺得這也是指關聯,因為我們也可以采用第三范式來實現,只是訂單在這種情況下會遇到好多的問題.
在訂單的設計中,我一般會有“條款ID”、“條款名稱”,也就是我會把主鍵對應上以后,把Name也帶過來,之所以要帶入"條款ID",主要還是因為訂單需要修改,在修改時,可以默認選中原來的值。而“條款名稱”的帶入就是我前面的說的原因。
因此,從這一點來說,這些確實是違背了“第三范式”。
#7樓 回復 引用 查看
2005-05-08 18:17 by lay
#8樓 回復 引用 查看
2005-05-08 18:58 by
我不想在訂單下達完以后,刪除了某條付款條款,導致這些訂單無法知道“真實的付款條款”了,這肯定不合理。
==為何要允許刪除付款條件?不可以設為失效嗎?
2我也不想,因為下了這張訂單了,而“嚴格控制”付款條款的“刪除”功能,這也不合理,憑啥不能刪除了?下個月這個“條款”確實永遠不會采用了。
==不能刪除就是不能刪除,規定下來不可以嗎?同樣,設為失效不行嗎?
3我也不想,付款條款修改后,導致以前所有采用此付款條款的訂單都變成新的條款,那在系統中的訂單如何與手頭的紙張訂單再對應,這肯定也不合理。
==付款條件可以隨意修改的嗎?同樣,需要修改的不可以新建一個條件嗎?
我認為,你的數據庫這樣設計是非常不成功的。就因為你上面的理由就造成成千上萬條記錄的冗余?這合理嗎?
一已之見,只承擔有限責任。。。
#9樓 回復 引用 查看
2005-05-08 19:26 by
#10樓 回復 引用 查看
2005-05-08 20:12 by
#11樓 回復 引用 查看
2005-05-08 20:29 by 一川煙草
#12樓 回復 引用 查看
2005-05-08 20:36 by 一川煙草
#13樓 [樓主] 回復 引用 查看
2005-05-08 21:27 by
上山砍柴去 :
其實我非常不想跟你討論這些問題,你說的幾個跟我的意思根本不是一回事。你可以用“是否有效”來實現,你的意思是所有的基礎都有“是否有效”,可客戶就是不喜歡這種“是否有效”的標志,"是否有效"是在客戶"暫時不用"的情況下會采用,知道什么叫"暫時"嗎?再者,時間一長你搞那么多"無效"的多惡心啊。
還有我說的就是能允許客戶刪除,你憑什么不讓客戶刪除,你以為這是給客戶考慮嗎?
自己去悟吧。
#14樓 回復 引用 查看
2005-05-08 21:52 by rIPPER
#15樓 回復 引用 查看
2005-05-08 22:10 by 一川煙草
#16樓 [樓主] 回復 引用 查看
2005-05-08 22:25 by
#17樓 回復 引用 查看
2005-05-08 22:40 by
#18樓 回復 引用 查看
2005-05-08 23:01 by
#19樓 回復 引用 查看
2005-05-09 00:12 by
個人意見,在數據庫里只添加新規則,不能改變已有規則,任何改動都視作新添加,這樣就能實現第三點了。不過這樣的數據也。。。
#20樓 回復 引用 查看
2005-05-09 00:57 by
#21樓 回復 引用 查看
2005-05-09 08:56 by
#22樓 [樓主] 回復 引用 查看
2005-05-09 09:15 by
老翅寒暑 :
我說的就是你指的意思,一張訂單已經確定,那么具有獨立性與歷史性。
@ 上山砍柴去 :
客戶說是保留,那你當然保留好了,我沒有否認這一點啊,但就怕客戶說不要保留,你卻偏偏要保留啊。至于數據冗余你看下面的。
至于“為什么還要ID呢?”就是有可能會進行修改,那么如果不帶ID過去,修改時如何選中默認值,要是不能默認選中,結果客戶修改只是為了修改其它的一個屬性,而這個ID可能會在不注意的情況下被修改掉了。因為是下拉框的。
至于作標記,也是一種方式,比如客戶說給作個標記或者是此值是應該具有“暫時不用”的情況,那么用標識當然是最好的。
就像老翅寒暑 說的,一張訂單是實物,在業務實際中明明確確存在,要是從法律上講也具有法律,就算沒有法律性,我們也要把它視為一個獨立性,有朋友說,以后修改怎么辦?一張訂單在當時下達,就具有當時的即時性與歷史性,不可能因為你以后的基礎數據的修改而導致訂單失去原來的屬性,因此這些所謂的“冗余”只是從"第三范式"上講的,而在實際的業務中,其實沒有所謂的“冗余”。
#23樓 回復 引用 查看
2005-05-09 09:39 by na
#24樓 回復 引用 查看
2005-05-09 09:41 by
#25樓 回復 引用 查看
2005-05-09 09:56 by
#26樓 [樓主] 回復 引用 查看
2005-05-09 10:20 by
小陸 :
ID可以考慮不保留,確實可以直接修改NAME,因為從某種意義上說,參考的數據COPY過來后,就認為已經確定了。
至于刪除的控制,有些基礎數據是需要使用“控制來限制的”,但不是全部。為何有人不思考實際中的一些差別呢。
na說有很多要隔離??也不是啊,具有獨立性與歷史性的實物,是建議要隔離的。
上山砍柴去說這么多人都是沒有經驗的??
我真不知道,是不是很有經驗的人跟你一樣,所有的基礎數據都采用“刪除控制”來做的,你可以去調查一下。
#27樓 回復 引用 查看
2005-05-09 10:37 by ayya__@hotmail.com
#28樓 [樓主] 回復 引用 查看
2005-05-09 10:41 by
對,如果那些需要“暫時”不用的,是應該要用標記來做的。應該可以修改狀態,也可以刪除吧,要是他們確實想刪除。
其實這種刪除不刪除無所謂了,問題是基礎數據應該COPY過去。
#29樓 回復 引用 查看
2005-05-09 10:59 by
#30樓 回復 引用 查看
2005-05-09 11:02 by
,一個表里的字段數如果太多,你說有沒有問題,比如有張表TestTable,里面包含了60多個字段,你認為這有不有問題?
#31樓 回復 引用 查看
2005-05-09 11:05 by
#32樓 [樓主] 回復 引用 查看
2005-05-09 11:15 by
#33樓 回復 引用 查看
2005-05-09 14:50 by
#34樓 回復 引用 查看
2005-05-09 15:30 by step
#35樓 [樓主] 回復 引用 查看
2005-05-09 15:38 by
你的觀點跟我們大致一樣,只是你可能沒搞清楚什么叫“付款條款”,英文名叫“Payment Term”,它不是一個2000字的協議,只是說明30天付款還是60天付款。
給你看個圖:

#36樓 回復 引用 查看
2005-05-09 16:46 by rIPPER
的 term在這里翻譯作條款,還要搞清楚?
term
n.
1.
A. A limited period of time.
B. A period of time that is assigned to a person to serve: a six-year term as senator. See Synonyms at period.
C. A period when a school or court is in session.
2.
以下略 ...
你們那兒做l10n的太爛了,趕快建議老板辭掉他 :)
#37樓 [樓主] 回復 引用 查看
2005-05-09 17:08 by
老兄,在SAP里全都翻譯成“付款條款”的!!
你查了查字典就以為可以想翻什么就翻什么嗎?
不了解ERP也不至于要把老板炒了吧???
早知道我就把文章寫成Payment Term了,那估計你肯定知道是什么意思了。哦,你不信的話用Google搜一下吧。
#38樓 回復 引用 查看
2005-05-09 18:35 by james wong
各人應用的環境不一樣,各人的經驗也不一樣。干嘛爭來爭去的?哪個你用好了沒問題就是對的,否則就是錯的。別人是對的你拿過來不一定是對的,別人是錯的也不一定在你那里就也是錯的。既然別人是對的你也不一定是對的,別人是錯的你也不一定是錯的,那這個問題也就是不對不錯的。那么,那么還要討論誰對誰錯做什么呢??
打雷了。。下雨了。。。大家快收衣服啊。。。
#39樓 回復 引用 查看
2005-05-09 19:17 by
#40樓 回復 引用 查看
2005-05-09 19:39 by rIPPER
#41樓 回復 引用 查看
2005-05-09 20:49 by
有道理喲,想問一下,一個表里的字段數如果太多,你說有沒有問題,比如有張表TestTable,里面包含了60多個字段,你認為這有不有問題?"
字段多不是問題,你可以去看看SPS的數據表Userdata,微軟為每一種數據類型預留了64個字段,該表的字段數超過300個,記錄數在100萬條以上,也沒有見嚴重影響性能.
很多時候,數據冗余是提升性能最有效的方法,特別是三個以上的表間聯接,通過數據冗余來改善性能是非常明顯的,同時也減小了SQL的復雜度.
#42樓 回復 引用 查看
2005-05-09 21:33 by 一川煙草
#43樓 回復 引用 查看
2005-05-09 21:42 by
#44樓 [樓主] 回復 引用 查看
2005-05-09 22:29 by
小陸 :
現在我現在討論根本不是指你說的冗余,我所指的這種冗余是必須,根本不需要同步不同步的。因為訂單的那些信息具有歷史性。從一點上來說,你說的冗余是另一回事。
#45樓 回復 引用 查看
2005-05-12 11:42 by 平常
我不想在訂單下達完以后,刪除了某條付款條款,導致這些訂單無法知道“真實的付款條款”了,這肯定不合理。
2我也不想,因為下了這張訂單了,而“嚴格控制”付款條款的“刪除”功能,這也不合理,憑啥不能刪除了?下個月這個“條款”確實永遠不會采用了。
3我也不想,付款條款修改后,導致以前所有采用此付款條款的訂單都變成新的條款,那在系統中的訂單如何與手頭的紙張訂單再對應,這肯定也不合理。
參照(Reference)
參照在數據庫設計中是一個比較復雜的問題,它是實現數據的完整性主要要素之一,詳細論述參考后面數據的約束。
在PowerDesigner中,可對參照完整性進行各項設置,參照的基數從0到n,對修改和刪除約束可分別設置為None、Restrict、Cascade、Set Null、Set Default。由于INSERT包含在UPDATE操作中,因此沒有單獨的INSERT約束。
約束的不同設置產生不同的效果,以修改為例(刪除相同):
None:父表修改,子表不影響。
Restrict:父表修改,如果子表存在,則出錯。
Cascade:父表修改,如果子表存在,則相應的修改。
Set Null:父表修改,如果子表存在,則相應置空。
Set Default:父表修改,如果子表存在,則相應置默認值。
#46樓 回復 引用 查看
2005-05-12 11:50 by 平常
◆ 表域完整性
通過主鍵來強制表的域完整性。
◆ 引用完整性
利用參照來加強表之間的邏輯關系。
◆ 數值域完整性
任何輸入的數據在類型和范圍上必須與指定的數據類型相匹配,只有當某列被說明允許NULL值,才允許向該列輸入NULL。
數據庫的性能測試
生成數據庫之后,應進行數據庫性能測試,以便優化數據庫的設計,因此需要生成測試數據,由于是性能測試,數據的規范性要求不高。通過PowerDesigner可方便地生成測試數據(Generate Test Data),完成性能測試。
數據的約束
O-O約束
對父表的INSERT、UPDATE、DELETE操作沒有限制。
M-O約束
對父表操作的約束:
父表的INSERT操作,對M-O約束,父表中間的記錄可以沒有任何約束地添加到表中,因為這種約束中不一定必須有子女。
父表的鍵值修改操作,只有在子表中其所有的子女對應均做修改后,才能修改,即一般采用級聯更新的方法。
父表的刪除,父親只有在其所有子女均被刪除或重新分配之后該父親才能被刪除。
強制對可選(M-O)約束
O-M約束
父表操作的約束:
父表的INSERT操作,對O-M約束,一個父親只有當至少當它的一個、子女同時被加入或至少存在一個合法的子女時,才能被加入。
父表的鍵值修改操作,只有當一個子女被創建或已經有一名子女存在才行。
父表的刪除,理論上刪除父親是沒有限制的,實際上,刪除主表記錄時,不采用級聯刪除子表的方案,而采用將子表的外鍵置空。
可選對強制(O-M)約束
M-M約束
父表操作的約束:
父表的INSERT操作,可能隨后需要生成子女,即在子表中創建新的行。也可能通過對子表的重新分配來實施完整行限制。
父表的鍵值修改操作,只有在子表對應的外鍵的值修改成新值時才能進行。實際可能是先創建新的父表紀錄,接著修改子表所有對應的紀錄,使其與父表的新紀錄關聯,最后刪除原父表紀錄。
父表的刪除,只有在子表中所有相關的行全部刪除或重新分配之后,才能刪除父表中的紀錄,一般對子表也進行刪除操作。
強制對強制(M-M)約束
在四類約束:M-M、M-O、O-M、O-O。鍵值的修改可能會改變表之間的關系,而且可能違反一些約束。違反約束的操作是不允許的。具體的應用必須根據實際的要求和商業規則進行適當的選擇。但在設計和開發時,必須考慮所分析的約束。
#47樓 回復 引用 查看
2005-05-13 01:26 by magic007
、要看開發的這個系統是個什么樣的系統,僅僅是一個OLTP系統,或者還要在系統上進行數據分析和數據挖掘。如果僅僅是一個事務處理系統,則以樓主所說的做法,行得通,否則的話,最好不要那樣做。
2、以我的經驗,數據冗余在開發上更方便一點,效率可能會高一點,但是后期可維護性和擴展性是比較差的。
3、關系數據庫一個核心的理念應該就是“關系”了,數據關系。設計數據庫,準確的說是設計數據模型,一是保證整個數據模型具有良好的擴展性,也就是說為以后業務的發展,需求的變化提供足夠的可擴展性。開發的方便來說應該是次要的,無非就是多點編碼。
4、在樓主的例子中,我從數據關系上談一下,訂單與客戶之間是很強的耦合關系,沒有客戶,那么訂單就沒有存在的意義。所以肯定是需要主外鍵關聯的。對于“付款條款”,在業務領域內,對于訂單來說是必須具備的,那么也需要主外健關聯。比如客戶有同名的情況,怎么標識多張相同客戶名的訂單是同一客戶還是不同的客戶?客戶改名了,如何標識改名前的訂單和改名后的訂單是同一張訂單?為了避免在客戶改名后,改名前的訂單的客戶名變成新的客戶名,可以在客戶表中建立組合主鍵,如cust_id與cust_seq_id。
#48樓 回復 引用 查看
2005-06-04 17:27 by
#49樓 回復 引用 查看
2005-06-07 21:45 by shewo
#50樓 [樓主] 回復 引用 查看
2005-06-08 08:20 by
:
老兄啊。你怎么還在講這個理論呢,前面的回復你看了嗎?我文章的主要目的就是寫給你這樣的人看的。
一般的人都是以為這樣想的,這個誰都知道,我的文章中也指出了,對于象訂單這種客觀存在的東西,不能死板的搬那種理論。
你說的這種數據不一致,你覺得需要保持嗎?已經成為歷史的訂單,你認為以后因為基本數據的修改,需要全部修改進去嗎?那么歷史訂單怎么辦??客戶會把已經完成的訂單存檔作為備案,你的意思是客戶還要把以前的訂單找出來一個個修改。。最好再理解一下我文章的意思。真沒想到,你什么也沒看懂。
#51樓 回復 引用 查看
2005-06-13 13:20 by skyworht
#52樓 回復 引用 查看
2005-06-13 21:01 by
#53樓 回復 引用 查看
2005-07-01 23:15 by min
#54樓 回復 引用
2005-08-04 15:54 by tx-zero [未注冊用戶]
#55樓 回復 引用 查看
2005-08-05 17:46 by
#56樓 回復 引用
2005-08-15 16:08 by nwc [未注冊用戶]
#57樓 回復 引用
2005-08-15 16:39 by nwc [未注冊用戶]
#58樓 回復 引用
2005-09-28 11:01 by 榴彈炮 [未注冊用戶]
#59樓 回復 引用
2005-09-28 12:45 by luckcp [未注冊用戶]
#60樓 回復 引用 查看
2005-11-08 23:37 by
#61樓 回復 引用 查看
2006-05-07 17:22 by
#62樓 回復 引用
2007-01-30 16:16 by 雨恨云愁 [未注冊用戶]
#63樓 回復 引用
2007-08-28 09:30 by zhanglin [未注冊用戶]
#64樓 回復 引用
2008-06-04 02:58 by solidco2 [未注冊用戶]
#65樓 回復 引用
2008-06-04 03:32 by 還是上面那個人 [未注冊用戶]
#66樓 回復 引用
2008-12-11 17:30 by 用版本控制來解決 [未注冊用戶]