APP下载

浅析考试系统的数据库设计与实现

2012-09-14刘锦培

海峡科学 2012年10期
关键词:主键数据量字典

刘锦培



浅析考试系统的数据库设计与实现

刘锦培1,2

1.福州大学数学与计算机科学学院;2.福建师范大学信息技术学院

数据库的应用设计在软件开发中的应用日趋广泛,它是数据库应用系统开发生命周期中的重要一环和系统开发成败的决定性一步。该文通过“考试系统”实例,深入分析数据库设计的基本原则和相关技巧。

数据库设计 主外键 检索 数据字典

数据库设计是指对于一个给定的应用环境,构造最优的数据库模式,建立数据库及其应用系统,有效存储数据,满足用户信息要求和处理要求。本文对数据库应用设计介绍以下几个方面内容:

1 主外键的使用

数据库中的主键是为了使记录能惟一标识,外键用来关联表与表之间的联系,主键和外键是把多个表组织为一个有效的关系数据库。可以通过主键和外键来了解数据库的设计架构,因此就出现以数据库为驱动的开发方式。开发人员根据数据库的设计和流程顺序开发程序,软件设计人员只需严格控制数据库的设计方向即可控制开发人员的开发过程。目前多数ERP或MIS系统都是按照这种模式进行,因为系统本身的特点就是过程化的,数据库驱动方式就是一种过程化的开发方式,也是一种较为简捷快速的开发方式。

这里,通过“考试系统”中的试题管理模块来体现主外键的使用。试题编号作为惟一标识来标识每道试题,而试题中的试题选项不该与试题放在同一张表中,而是通过另一张试题选项表来管理,此时试题选项表中的试题编号就要外键关联试题表中的试题号,试题选项表再通过试题编号和其自身的选项编号来组合起来作为主键惟一标识,详细表设计如下:

Create table T_Subject(

SubjectID int,

Descriptions text

Primary key(SubjectID))

Create table T_SubjectOption(

SubjectID int,

OptionID int,

Descriptions text

Primary key(SubjectID,OptionID),

Foreign key(SubjectID) references T_Subject(SubjectID))

通过以上表设计,可以保证在试题选项表T_Subject- Option中的试题号都可以在试题表T_Subject中找到,体现了数据的相互依赖关系,同样通过这样的表结果可以看出试题表与试题选项表之间的关系。

2 数据字典的设计

数据字典(Data Dictionary)是一种用户可以访问的记录数据库和应用程序元数据的目录。其特点是供人查询对不了解的条目的解释,数据量基本有限,在软件中用于搭配其他模块的属性选择,比如“考试系统”中安排考试的时候下拉选择年级、专业、班级等字典信息,常规的设计方法是每个属性设计一张字典表,如:

年级表

Create table T_Grade(

GradeID char(10),

GradeName varchar(100),

Primary key(GradeID))

专业表

Create table T_Major(

MajorID char(10),

MajorName varchar(100),

Primary key (MajorID))

此时只需对这些数据字典表进行编辑即可,但是这样的设计还会存在些问题,这里专业代码MajiorID是主键,不允许重复,且一旦被其他模块选中后,则不允许再被修改,在实际软件使用过程中经常会有需要修改键值属性的时候,比如“网络系统管理”这个专业的专业代码原来是“wlxtgl”,软件经使用后发现代码太长,不方便用户记忆使用,需要将其缩短为wg,而按照以上字典设计就无法再进行修改代码。

当然,数据库中可以将这些关联表的外键设置级联更新,实现专业代码更新,其他有关联的模块都级联更新过来,可想而知,当数据量少的时候级联更新没问题,当数据量大的时候,级联更新就变得很慢,会造成极大的资源浪费,而且在编辑数据字典时,主键的重复判断也不好处理,有什么方法可以解决这些问题呢?不妨看如下表设计结构:

Create table T_Major(

MajorID int identity,

MajorCode char(10) unique,

MajorName varchar(100),

Primary key(MajorID))

以上设计是将主键用自动增长类型来实现,由数据库来控制表中记录的惟一性,此时程序就无需担心表记录的重复,而专业编号由另一个属性MajorCode来表示,且该属性设置成unique(惟一),在其他模块关联专业的主键MajorID,并不关联MajorCode,程序可以通过视图来读取MajorCode,这样就可以实现专业代码允许用户修改(即使专业代码已被其他模块关联使用),似乎这样的表结构设计已经满足了我们数据字典的要求,编程人员也很方便实现,这样的设计结构并没有真正发挥数据字典的特点。

上文提到,数据字典的数据特点是数据量少(相对其他模块数据而言数据量相对少很多),属性比较单一,一般只有主键和值组成。要是按照以上设计方法就会导致每个字典数据都要创建一张表,而且表中的记录就几十上百。例如“考试系统”中的专业表,一个学院乃至一个学校,最多也就上百个专业,用一张表来存储较为浪费,浪费些磁盘空间没关系,问题是实际软件中数据字典会非常多,从而就得创建很多表来管理数据字典。并且有一点非常被动的就是,当你要添加一个数据字典的时候,就要再添加一张表来支持。比如在财务软件中经常需要添加字典数据,要是按照这样的方法来设计数据字典的话,那数据库中会有百张表都是数据字典,这会给开发人员就会带来极大的不便。综合以上分析,得出的结论就是得想办法将多张数据字典表给合并到一个地方,统一来管理。由于数据量并不是很大,合并后的数据量对现有的数据库软件来说也不会有太大压力,可以考虑将多个数据字典表合并成一张表来处理,具体设计如下:

Create table T_DataDictionary(

DataDictionaryID int identity,

DataDIctionaryType char(10),

DataDictionaryCode char(10 ) unique,

DataDictionaryName varchar(100),

Primary key(DataDictionaryID))

在DataDictionaryType中存储的就是数据字典的类型,比如“考试系统”中数据字典类型有:学期(Term)、年级(Grade)、专业(Major)、班级(Class)等等。在此数据字典的设计似乎可以告一段落,但实际软件开发过程中远远不够,数据之间会有复杂关系,比如年级与专业的关系,一个年级有那么多个专业,不同年级下的专业有可能不大相同,那在设计数据字典的时候怎么保证数据字典之间的关系呢?而且在实际使用过程中关系有可能嵌套,比如一个年级下有多个专业,一个专业下又有多个班级,难道我们要再通过两张表来记录他们之间的关系吗?要是这样的话,那关系多的话,岂不是关系表又越来越多,又回到了之前字典表太多的问题上?这样设计固然可用,但并不科学,有没有办法能够实现父与子关系的结构(树形结构),这里我们就应用父子表的概念来设计数据库中数据字典之间的关系,表设计如下:

Create table T_DataRelation(

DataRelationID int not null,

ParentDataRelationID int null,

primary key (DataRelationID),

foreign key(DataRelationID) references T_DataDictionary(DataDictionaryID),

foreign key(ParentDataRelationID) references T_DataDictionary (DataDictionaryID));

程序可以通过一个递归算法来构造出字典数据之间的关系,关系可以是多级树形结构也可以是一级平行结构。在这里,我们数据字典的设计才算基本完成,当然,在实际软件实施过程中还会有些其他的功能需求,在设计上还需要加以调整,而一般软件的数据字典通过以上两张表来管理即已足够。

可能会发现,为什么在设计表的时候Code列的字段类型都用char类型,而不用varchar类型,这因为char类型是固定长类型,在检索的时候比varchar类型要快的多,而且在SQLSever老版本的数据库上用varchar类型做主键,数据量大时会导致检索出错,所以一般比较固定的列或比较经常要检索的列的属性都设置成固定长度类型。

3 数据检索技巧

数据库中对数据的检索有多种,一般会以视图的形式表现出来,例如学生信息表。

学生表:

Create table T_Student(

StudentID int,

StudentCode char(12),

StudentName varchar(100),

MajorID int,

GradeID int,

ClassID int,

Primary key(StudentID))

学生视图:

Create view V_Student

As

Select

a.StudentID,

a.StudentCode,

a.StudentName,

a.MajorID,

b.MajorName,

a.GradeID,

c.GradeName,

a.ClassID,

d.ClassName

From T_Student a

Left join T_Major b on a.MajorID = b.MajorID

Left join T_Grade c on a.GradeID = c.GradeID

Left join T_Class d on a.ClassID = d.ClassID

假设学生表经多年使用后数据量非常庞大,要在其中找出专业名称为“网络系统管理”学生的所有信息,自然想到直接查询视图,条件锁定在专业名称,SQL语句如下:Select * from V_Student where MajorName =‘网络系统管理’

若学生数据量并不多,使用视图来检索并不会慢,但是当数据量大的时候检索就会变得非常慢,其原因就在于视图中左连接了三张数据字典表,若使用视图来检索,数据库内部的操作流程是首先对学生表中的所有记录左连接这三张数据字典表,然后再去检索专业名称为“网络系统管理”学生,检索速度慢是因视图内部的左连接了所有的数据导致,应该先找出指定专业的学生,然后左连接专业、年级、班级到这些指定专业的学生上,这样就大大减少了左连接的数据量,因此类似于这样的检索数据就不能用视图来完成,需要实时编写SQL语句来满足不同的需要,按照以上要求改造后的SQL语句如下:

Create view V_Student

As

Select

a.StudentID,

a.StudentCode,

a.StudentName,

a.MajorID,

b.MajorName,

a.GradeID,

c.GradeName,

a.ClassID,

d.ClassName

From(Select * from T_Student where StudentID=( Select MajorID from T_Major where MajorName ='网络系统管理')) a

Left join T_Major b on a.MajorID = b.MajorID

Left join T_Grade c on a.GradeID = c.GradeID

Left join T_Class d on a.ClassID = d.ClassID

经改进后的SQL语句变得非常复杂,因此在实际开发过程中可以考虑用存储过程来实现,将复杂的SQL语句写入存储过程中。如果经常对某些列,比如学号列、专业列等要频繁做检索操作,可以考虑在其表上对这些列创建索引,这样可以加快检索索引。

4 结束语

数据库的设计要结合软件的需求来完成。随着时间的推移,软件的需求是不断变化的,一个好的数据库设计必须能适应其需求的变化。当然在很多情况下无法适应,这时就要做详细的分析,判断是否重构系统,如果前期设计得当,将大大减轻软件在后期的使用和维护方面的工作量,而目前许多软件开发在前期细节方面投入不多,导致后期修改的工作量加大,这是本文讨论数据库设计中应注意的细节问题。

[1] 吴爽.软件开发中的数据库设计的理论和实践[J].计算机光盘软件与应用, 2011(6): 182.

[2] 李维. Delphi MDA/DDA程序设计——使用ECO[M]. 北京: 电子工业出版社, 2007.

猜你喜欢

主键数据量字典
基于Go 实现的分布式主键系统研究
基于大数据量的初至层析成像算法优化
计算Lyapunov指数的模糊C均值聚类小数据量法
高刷新率不容易显示器需求与接口标准带宽
宽带信号采集与大数据量传输系统设计与研究
基于外键的E-R图绘制方法研究
字典的由来
我是小字典
正版字典
数据库主键设置探讨