每年在带毕业设计时,学生设计数据库都有不少问题。在应用软件的开发中,数据库设计是个要紧的工作。数据库原理中学过数据库设计,在一些相关的实践环节中,数据库设计也是重要的环节。其中,重描述(语言层面的),轻设计的成份很明显。而作为一个软件工程师,实际上,设计能力还是首要的。这是大学生学习中必须要注意的事。
关系数据库的设计有一套成熟的做法,也有很完善的理论支持。所谓成熟的做法,要经过需求分析、概念结构设计、逻辑结构设计、物理结构设计、数据库实施、运行和维护等多个步骤完成,前人开发出了各种工具支持这一过程,以达到方便设计人员,便于交流合作的目的。而完善的理论,指的是规范化理论,在数据依赖概念的支持下,用几级范式,用于评价关系模式。计算机科学是善于构造的科学,实际上,评价的过程和方法就指明了设计的原则,体现了设计的手段。可以追求较高的范式,不断优化所设计的关系模式。
规范的设计方法有利于开发人员的合作,有利于保证设计的质量,但是需要经过较多的环节,需要耗费较多的开销。在实际工作中,尤其是在一些小型系统的开发当中,人们经常利用经验,在对应用系统调研完成后,很快地完成设计。
所谓经验是人们在长期工作过程中形成的,经验体现为一些规则。规范的设计方法来源于经验,是对开发方法的总结,同时经验同规范的方法并不冲突,经验是按照规范的设计方法在工作过程中形成的一种潜意识。往往经验丰富的设计人员根据调研中收集到的现行系统中的单据、表格,经过一定构思后将直接形成设计结果。当然,经验设计的质量取决于设计人员的经验。
所以,在毕业设计规模的应用开发中,不妨也就体验下这些经验。需要声明的是,在求学阶段,正道要走,数据库原理中的那些理论是计算机类专业学生的真正功底,值得深究。而本文的实用方法不免显得不严格,不够档次,但是对不能由理论联系到实际的同学,不妨先能用着直观的方法,做点质量还算说得过去的工作,再回去体味理论,也算是条路子。
本文中不少的文字,来自十多年前我编写的教材的一部分。这本教材现在已经没有人用,出版社也都没有了,这次挖出来,没有版权的问题,算是发挥余热。
闲言碎语不讲了,进正题。
一、经验设计中经常运用的数据库设计原则
1、同一列(字段)的数据只能是单一的数据类型
如货物金额不能和货物的单位在同一列。但有时可以在同一列中存放数据类型相同但含义不同的数据,如帐目中的贷方、借方,它们的数据类型相同,由于不可能在同一行借贷同时发生,所以借、贷可以共用一列,这时必须确保能够相互区分,可以规定借方为正,贷方为负或者再用一列标识当前记录是借或贷。
2、 一个关系只反映一个主题
这意味着表中的一条记录只定义单独的一件事情,不要将多个实体都塞入一个表中。如果两个实体之间有多对多和一对多的关系,需要将两个实体分别对应一个表,它们的联系也做成一个表。例如学生选课的数据库,应该将学生和课程放在不同的表中,在另外一个表中存放学生和课程的联系;再比如一个关于汽车和驾驶员的数据库,如果一个驾驶员可以驾驶多种类型的汽车,也应该用上述策略。如果两个实体之间是一对一的联系,如一个驾驶员只能驾驶一种类型的汽车,则为了减少数据库中表的个数,可以在一个表中描述两个实体及它们的联系,并且这是一种比较好的处理办法。
3、同一实体只在数据库中出现一次
一个数据库由若干个表组成,应该保证相应于每个实体的描述只在数据库中出现一次。否则,一方面存在数据冗余,另一方面在更新这些实体的信息时,必须在所有出现相应信息的地方都要更新,稍有疏忽就会出错,造成系统中数据的不一致。
4、能通过简单计算得到的数据不保存
经过简单计算就可以得到的值一般不保存,例如保存了单价和数量后,金额不再保存。如果保存了这样的数据,当相关数据变化时就必须要求计算值也要变化,这无疑要加重应用程序的负担。我们只要在使用到这些计算值时再去计算就行了,这样总能取得最新的值,这对于以计算速度为优势的计算机来说是不成问题的。有人在设计数据库时,还要专门建立表存放统计结果,这也是没有必要的。
5、信息量大,但取值固定的列应建立编号体系
建立并使用编号体系的最大好处在于便于管理和节约存储空间。例如,在保存图书信息的表中,需要用到出版社信息,若直接记录每本书的出版社名,每条记录大概需要20个字节左右。如果能够建立一个关于出版社信息的表,每个出版社都惟一编号,这个编号用几个字节就够了。可想而知,一个图书馆的图书成千上万,节约的存储空间是非常可观的。图书数量越大,这种效果越好。
使用编号,一般首先要考虑是否有国家标准。如果有,一定要使用标准,这样的系统是开放的、易于扩充的。如果没有现成的编号体系,可以协助用户制定。在编号中可以体现记录的某个特征或多个特征,例如学生学号取作“97091B101”,其中包含了年级(97级)、所在系(09)、专业(1)、本科或专科(B或Z)、班号(1)和学生序号(01)。
6、保证每个表中的记录是惟一的
记录的惟一性是关系的基本性质,但在很多的DBMS中却不是强制要求的。这就需要我们在数据库设计时能够指定关系的关键字,由关键字保证记录的惟一性。通常由单一字段充当,并且一般是编号,也可由多个字段共同构成关键字。
7、为方便用户操作,需要建立一些辅助的表
有些内容的取值相对固定,如果由用户直接输入,影响操作速度,还容易出错。这时可以将这些值保存到一个表中,实现“代码录汉字”,或用开发工具中提供的列表或组合框实现录入。之所以将这些信息放在一个表中,是因为这些数据有可能会发生变化,还需要动态地修改。例如图书管理系统中可能不关心出版社的信息,但为了方便用户录入图书信息中出版社字段的值,可以用一个专门的表保存出版社的信息。
8、反映规则的数据可以考虑保存到一个辅助表中
例如在图书管理系统中,不同身份的读者允许借书的数目是不一样的,如研究生每次可借10本,本科生每次只可借7本,这就是借书的规则。可以将反映这种规则的数据体现在程序中,但这时,一旦允许借书的数量改变了,即规则改变了,你必须改变程序。如果这样的信息保存在一个表中,当规则改变时,只要修改这个表中数据就可以“平稳过渡”,甚至我们还可以加入新的身份的读者。这使得系统的适应能力和可扩充性大增。
按上述经验设计之后,要对照系统功能,看是否还有其他要处理的数据没有考虑进来。数据库能够真实反映现实世界的状态,这是对数据库的基本要求。现实世界中的实体及实体间的一对一、一对多及多对多的联系必须体现在各个表中,要认真检查,防止遗漏。另外,可以结合规范化的方法,对设计结果进行优化。
一般来说,经过上述的步骤,是能够得到一个说得过去的设计的。
二、一个实例
例:某仓库发货单和订货单的样式如下图所示,设计一个数据库,保存有关信息。
1、方案1
根据表中的内容,可以直接设计出:
- 订货单(编号,订货日期,收货单位,地址,收货人,收货地点,序号,零件编号,名称,规格,原厂编号,数量)
- 发货单(编号,发货日期,收货单位,地址,收货人,收货地点,订单编号,订单收到日期,序号,零件编号,名称,原厂编号,数量,尚缺数量)
在这个方案中存在的缺陷和解决办法如下:
(1)订货单与发货单编号和数量在命名上有冲突。
(2)由于每个订货单和发货单上都有多个零件,订货单和发货单的基本信息有冗余,从函数依赖角度讲是零件名称等属性对关键字存在部分函数依赖,应该将单据的基本信息同该单据上的零件分别放在不同的表中。
(3)序号只是方便人看的,无需在数据库中保存,只要将来在打印时产生一个顺序的值即可。
根据以上意见,得出方案2的设计。
2、方案2
- 订货单1(订单编号,订货日期,收货单位,地址,收货人,收货地点)
- 订货单2(订单编号,零件编号,名称,规格,原厂编号,订货数量)
- 发货单1(发货单号,发货日期,收货单位,地址,收货人,收货地点,订单编号,订单收到日期)
- 发货单2(发货单号,零件编号,名称,原厂编号,发货数量,尚缺数量)
方案2中仍存在的缺陷及解决办法如下:
(1)零件的信息在订货单2和发货单2中仍有冗余,从函数依赖角度讲是零件名称等对关键字的部分函数依赖,可以将有关零件的信息放在专门的表中。
(2)对尚未发出的订货数量,即缺货数量的控制应该在订货单中进行,缺货数量属性应该放在订货单2中。因为发货单是根据订货单制作的,不能多发,某次发货量不足时要做记录以便下次再发,在现行手工系统的单据上体现在发货单中是为了让收货人清楚,而发货方必须在另外的帐本上记录。在录入订货单时,订货单2中的缺货数量自动取得订货数量,发货时,缺货数量改写为当前缺货数量减去发货数量。发货单2中不需要尚缺数量,因为根据订货单2中的缺货数量和发货单2中的发货数量,尚缺数量可以在打印发货单时得出,只要对相关的表进行连接即可。
(3)发货单1中的收货单位、地址、收货人、收货地点、订单收到日期没有必要保存,因为这些是订货单的信息,发货单1中只记录本次发货是针对哪一次订货的就足够了。
根据以上意见,得出方案3的设计。
3、方案3
- 零件清单(零件编号,名称,规格,原厂编号)
- 订货单1(订单编号,订货日期,收货单位,地址,收货人,收货地点,订单收到日期)
- 订货单2(订单编号,零件编号,订货数量,缺货数量)
- 发货单1(发货单号,订单编号,)
- 发货单2(发货单号,零件编号,发货数量)
对于以上方案,假如各订货单位的地址、收货人、收货地址等都是固定的,还有必要分解出一个订货单位清单以减少订货单1中的冗余数据。
从例子中可以看出,数据库中保存数据的内容和和结构同它的外部表现形式(单据、帐本等)是不相干的,要符合计算机特点,方便在DBMS中实现。不要太迁就计算机,而对人不方便,通过设计程序仍然可以让数据以人习惯的表现形式展现在用户界面上,只要在数据库中指定这些表之间的联系并在程序中对这些表进行一些基本的关系运算即可。
三、总结
在示例看着单据直接写出关系模式,实际上心中还是要有实体、实体联系一干的内容,只不过,不想概念,结果就出来了,这是用规范的步骤方法走过后应该有的感觉,这就是经验,并且是管用的经验。而后看到的不断优化的过程,实际起支柱作用的是数据依赖、范式。通过做些实践,将这些所谓“枯燥”的东西与实际应用联系起来,这是作为专业的学生该达到的境界。
四、练习
找一张你日常生活中可以遇到的单据,比如一张发票(简单)、一张课程表(稍复杂)、几张办同一件事情中用过的单据(贴近实际了),设计出支持相关业务的数据库。(1)可以随意设计出来,依据经验设计的原则作出补充或改进;(2)或者直接套用经验设计原则,给出设计;(3)读一读教材,用规范的方法做一次设计,并与前述随意的设计作对照。