冗余有时候显得非常有必要,而且是不得不。2010-01-06
关于数据库的第三范式的定义这里就不进行描述了。总之这些基础概念大家还是要有大概的理解的,至少要记得住这个概念的名字。实在话,一切源自实践,亲身体会出真知。但作为知识的使用者——实践参考理论。
恩师曾经嘱咐我们,数据库设计至少要遵循第三范式。当时把老师的话奉若神明,在一些课程设计中用着还挺合适。岂不知外面是一个丰富多彩的世界,在这个丰富多彩的世界中充斥着变幻莫测的数据。按照第三范式能完成任务吗?能完成“上帝”给我们的要求吗?
当然是不能的……
通过手头上一丁点的项目经验,我总结出来如下的数据形式的存在。
1.现实世界中发生的数据必须一直保持着原来持有的数据意义,它发生后就和整个世界隔离了,它只属于那一刻。
2.现实世界中发生的数据必须受着外界的影响,它溶于世界。(这个很好处理,遵守第三范式的数据库设计即等于实现)
说明上面两种数据形式的存在和处理方法,下面举例说明(举例子,我都举大家都比较熟悉的业务示例,大家都从学校里面走出来的)
学生成绩管理系统:
GId | GradeName |
1 | 一年级 |
2 | 二年级 |
3 | 三年级 |
CId | GId | ClassName |
1 | 1 | 一班 |
2 | 1 | 二班 |
3 | 2 | 一班 |
4 | 2 | 二班 |
CId | StuId | StuName |
1 | 1 | 李一 |
1 | 2 | 李二 |
3 | 2 | 张大 |
2 | 5 | 张小 |
1 | 4 | 钱偲 |
2 | 2 | 尔耳 |
2 | 3 | 钱五 |
下面来设计成绩表吧:
如何设计呢,按照第三范式,我们应该这样设计。分别有StuId做外键关联学生,CourseId做外键关联具体的课程,Exam对应某次具体的考试。
其中文表述方就是:某个学生某次考试某门课程的成绩
StuId | CourseId | Score | Exam |
看上去合情合理,像那么回事,也深得第三范式的认可。但是在实际应用中并非如此,可以这样说这样设计的数据库表只能在系统的某个阶段适用,过了这个阶段随着大环境的改变,这张表将存在严重的问题,其后果是统计结果错误。
假想,一个学年过去了,该升级的升级,该留级的留级,该换班的换班。去年一年级一班的李一进了二年级一班了,教务处也将学生信息调整好了,即将李一的CId改为3,其他学生同理(不管是系统自动改,还是手工改,反正总之有这么一个步骤)。
有这么一个闲的无聊的老师,想把原来一年级一班的学生成绩打印出来看看。还打的出来吗????打不出来了,麻烦了,因为以前的学生成绩跟着学生来到了二年级了!糟糕啊!还没考试就有成绩了!也怪这个老师无聊,把这个bug发现了。呵呵,玩笑话,该来的总是要来,这个时候只能坦然面对。
分析下,原来这个学生成绩表中的数据就属于以第一种形式存在的数据—— 1.现实世界中发生的数据必须一直保持着原来持有的数据意义,它发生后就和整个世界隔离了,它只属于那一刻,即保证成绩表能记录下成绩数据发生时它是某个年级某个班级某个学生某次考试某门课程的成绩,说白了这个数据要记录下它发生时的整个世界的状态(理论上是这样,但是没必要),它拥有回顾历史,具有文物般的价值 ,那么这么设计吧(至少在一般的系统的能适用)
GId | CId | StuId | CourseId | Score | Exam |
如果实际当中这样设计还不能回到过去(例如:班级名和年级名都有可能会改变,这样的设计还是不行,那你就得把班级名和年级名记录下来 ),那就得慢慢考究了,呵呵~!
2010-01-06 22:22:16