在博客园上看到了一篇关于数据库范式的文章《数据库设计中的五个范式》:
第三范式规则查找以消除没有直接依赖于第一范式和第二范式形成的表的主键的属性。我们为没有与表的主键关联的所有信息建立了一张新表。每张新表保存了来自源表的信息和它们所依赖的主键。
关于第三范式的思想,我想有很多朋友都熟悉,在数据库设计时,也是我们尽可能采用的范式之一,第三范式的出发点是什么?就是尽可能的减小“数据冗余”、并也能得到“数据”的整洁性,提高维护性,不容怀疑,第三范式是我们努力、必须要去遵从的。
然而,有很多朋友把第三范式作为“不死的法宝”,但其实在实际的应用中,我们还是要从不同的业务出发,要合理的应用“第三范式”。下面我也就简单的举个例子:
一张订单会关联很多的基础资料,如:客户,付款条款,货运方式等,这些信息是有专门表进行维护的,在下订单时也是用下拉框选择的,在保存订单信息时,按照“第三范式”的要求,那应该只保存对应的主键值就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 用版本控制来解决 [未注册用户]