一、设计数据库的必要性
- 1. 为什么要设计数据库
当数据库比较复杂(如数据量大,表较多,业务关系复杂)时,我们需要先设计数据库,
因为:
- 良好的数据库设计:
- 节省数据的存储空间
- 能够保证数据的完整性
- 方便进行数据库应用系统的开
- 糟糕的数据库设计:
- 数据冗余、存储空间浪费
- 数据更新和插入的异常
二、软件项目开发周期中的数据库开发
- 1. 数据库生命周期
数据库的生命周期主要分为四个阶段:
- 1. 需求分析阶段:(此阶段在软件项目开发周期中的需求分析阶段进行)这个阶段主要是收集并分析用户的业务和数据处理需求
- 收集信息(我们需要与数据的创造者和使用者进行访谈。对访谈获得的信息进行整理、分析,并撰写正式的需求文档。需求文档中需包含:需要处理的数据;数据的自然关系;数据库实现的硬件环境、软件平台等;)
- 标识对象
- 标识每个对象的属性
- 标识对象之间的关系
- 2. 逻辑设计阶段:(此阶段在软件项目开发周期中的概要设计和详细设计阶段进行)
使用ER或UML建模技术,创建概念数据模型图,展示所有数据以及数据间关系。最终概念数据模型必须被转化为范式化的表。
- a. 绘制E-R图
- b. 将E-R图转换为表格
- c. 应用三大范式规范化表格
- 3. 物理设计阶段:
根据特定数据库管理系统所提供的多种存储结构和存取方法等依赖于具体计算机结构的各项物理设计措施,对具体的应用任务选定最合适的物理存储结构(包括文件类型、索引结构和数据的存放次序与位逻辑等)、存取方法和存取路径等。这一步设计的结果就是所谓“物理数据库”。
- a. 数据库物理设计的目标是尽可能优化性能。
- b. 物理设计阶段,表结构可能需要进行重构来满足性能上的需求,这被称为反范式化。
- c. 反范式化的步骤包括:
- I. 辨别关键性流程,如频繁运行、大容量、高优先级的处理操作
- II. 通过增加冗余来提高关键性流程的性能
- III. 评估所造成的代价(对查询、修改、存储的影响)和可能损失的数据一致性
- d. 实现维护阶段:
- I. 当设计完成之后,使用数据库管理系统(DBMS)中的数据定义语言(DDL)来创建数据结构。
- II. 数据库创建完成后,应用程序或用户可以使用数据操作语言(DML)来使用(查询、修改等)该数据库。
- III. 一旦数据库开始运行,就需要对其性能进行监视。当数据库性能无法满足要求或用户提出新的功能需求时,就需要对该数据库进行再设计与修改。这形成了一个循环:监视 –> 再设计 –> 修改 –> 监视…。
三、数据库设计实现步骤
- a. 需求分析阶段
- I. 收集信息
与该系统有关人员进行交流、坐谈,充分理解数据库需要完成的任务
- b. 标识对象(实体-Entity)
标识数据库要管理的关键对象或实体
- 3. 标识每个实体的属性(Attribute)
- 4. 标识对象之间的关系(Relationship)
- 2. 逻辑设计阶段
- 1. 绘制E-R图
实体关系图(Entity Relationship Diagram),是指提供了表示实体型、属性和联系的方法,用来描述现实世界的概念模型。
ER模型中的基本元素
基本的ER模型包含三类元素:实体、关系、属性
元素说明:
- 1. 实体(Entities):实体是首要的数据对象,常用于表示一个人、地方、某样事物或某个事件。一般名称单词的首字母大写。
辨别强实体与弱实体:
- 在现实世界中,有时某些实体对于另一些实体有很强的依赖关系,即一个实体的存在必须以另一实体的存在为前提。前者就称为“弱实体”,后者称为“强实体”。比如在人事管理系统中,职工子女的信息就是以职工的存在为前提的,子女实体是弱实体,子女与职工的联系是一种依赖联系。
- 强实体内部有唯一的标识符。
- 弱实体(weak entities)的标识符来自于一个或多个其它强实体。弱实体用双线长方形框表示,依赖于强实体而存在。
- 2. 关系(Relationships):关系表示一个或多个实体之间的联系。关系依赖于实体,一般没有物理概念上的存在。
关系最常用来表示实体之间,联系可分为以下 3 种类型:
- 一对一联系(1 ∶1) :例如,一个部门有一个经理,而每个经理只在一个部门任职,则部门与经理的联系是一对一的。
- 一对多联系(1 ∶N) :例如,部门与员工之间存在一对多的联系“所属”,即每个部门可以有多个员工,但是每个员工只能隶属一个部门
- 多对多联系(M ∶N) :例如,学生与课程间的联系(“学 ”)是多对多的,即一个学生可以学多门课程,而每门课程可以有多个学生来学。联系也可能有属性。例如,学生“ 学” 某门课程所取得的成绩,既不是学生的属性也不是课程的属性。由于“ 成绩” 既依赖于某名特定的学生又依赖于某门特定的课程,所以它是学生与课程之间的联系“ 学”的属性。
关系的构图是一个菱形,关系的名称一般为动词。
- 3. 属性(Attributes):属性为实体提供详细的描述信息。一个特定实体的某个属性被称为属性值。Employee实体的属性可能有:emp-id, emp-name, emp-address, phone-no……。属性一般以椭圆形表示,并与描述的实体连接。
属性可被分为两类:
- a. 标识符(identifiers):Identifiers可以唯一标识实体的一个实例(key),可以由多个属性组成。ER图中通过在属性名下加上下划线来标识。
- b. 描述符(descriptors):多值属性(multivalued attributes)用两条线与实体连接,eg:hobbies属性(一个人可能有多个hobby,如reading,movies…)。复合属性(Complex attributes)本身还有其它属性。
- 1. 绘制实体对象及关系
- 2. 确定表之间的关系,完成E-R图
- 2. 将E-R图转换为表
- 具体做法
- 1. 实体类型的转换
- a. 将每个实体类型转换成一个关系模式。
- b. 实体的属性即为关系模式的属性。
- c. 实体标识符即为关系模式的主键。
标识每个表的主键列,需要注意的是:没有主键的表添加ID编号列,它没有实际含义,用于做主键或外键,例如用户表中的“UID”列,版块表中添加“SID”列,发贴表和跟贴表中的“TID”列
注意:《database system concepts》里面提到主键的定义是表中唯一的标识,“应该选择从不变化或极少变化的属性”。
否则,建议大家根据实际情况使用没有意义的逻辑主键
在表之间建立主外键,体现实体之间的映射关系
- 实体间关系的转换
- a. 对于二元联系,按各种情况处理,如下面所示。
二元关系 |
ER图 |
转换成的关系 |
联系的处理 |
主键 |
外键 |
1:1 |
(2个关系) 模式A 模式B |
(有两种) 处理方式1:把模式B的主键,联系的属性加入模式A 处理方式2:把模式A的主键,联系的属性加入模式B |
(略) |
(依据联系的处理方式) 方式1: 模式B的主键为模式A外键 方式2:表A的主键为表B的外键 |
|
1:N |
(2个关系) 模式A 模式B |
把模式A的主键,联系的属性加入模式B |
(略) |
模式A的主键为模式B的外键 |
|
M:N |
(3个关系) 模式A 模式B 模式A-B |
联系类型转换成关系模式A-B; 模式A-B的属性: (a)联系的属性 (b)两端实体类型的主键 |
两端实体类型的主键一起构成模式A-B主键 |
两端实体类型的主键分别为模式A-B的外键 |
转换步骤:
(1)把三个实体类型转换成三个模式:
①系(系编号,系名,电话)
②教师(教工号,姓名,性别,职称)
③课程(课程号,课程名,学分)
(2)对于1:1联系“主管”,可以在“系”模式中加入教工号(教工号为外键)。
①系(系编号,系名,电话,主管人的教工号)
对于1:N联系“聘用”,可以在“教师”模式中加入系编号和聘期两个属性(系编号为外键)
②教师(教工号,姓名,性别,职称,系编号,聘期)
(3)第三步:对于M:N联系“任教”,则生成一个新的关系模式:
①任教(教工号,课程号,教材)
(4)第四步:转换成以下模式:
关系模型 |
主键 |
外键 |
系(系编号,系名,电话,主管人的教工号) |
系号 |
主管人教工号 |
教师(教工号,姓名,性别,职称,系编号,聘期) |
教工号 |
系编号 |
课程(课程号,课程名,学分) |
课程号 |
|
任教(教工号,课程号,学分) |
教工号,课程号 |
教工号,课程号 |
- b. 一元联系类型的转换
和二元联系类型的转换类似。
职工之间存在上下级联系,即1:N联系
可以转换成以下模式:
关系模型 |
主键 |
职工(工号,姓名,年龄,性别,经理工号) |
工号 |
工厂的零件之间存在着组合关系(M:N联系)
①零件(零件号,零件名,规格)
②组成(零件号,子零件号,数量)
可以转换成以下模式:
关系模型 |
主键 |
零件(零件号,零件名,规格) |
零件号 |
组成(零件号,子零件号,数量) |
零件号,子零件号 |
- c. 三元联系类型转换
(1)若实体间联系是1:1:1,可以在三个实体类型转换成的三个关系模式中任意一个关系模式的属性中加入另两个关系模式的键(作为外键)和联系类型的属性。
(2)若实体间联系是1:1:N,则在N端实体类型转换成的关系模式中加入两个1端实体类型的键(作为外键)和联系类型的属性。
(3)若实体间联系是1:M:N,则将联系类型也转换成关系模式,其属性为M端和N端实体类型的键(作为外键)加上联系类型的属性,而键为M端和N端实体键的组合。
(4)若实体间联系是M:N:P,则将联系类型也转换成关系模式,其属性为三端实体类型的键(作为外键)加上联系类型的属性,而键为三端实体键的组合。
三元联系的ER图
1:1:1关系 技术员在项目中使用手册的关系
说明:
- 一名技术主管对于每一个项目使用一本说明手册
- 一本说明手册对于每一个项目属于一名技术主管
- 一个项目有一个技术主管一本说明书
可以转换成以下模式:
关系模型 |
主键 |
Technician(TechnicianID,TechnicianName) |
TechnicianID |
Notebook(NotebookID,NotebookName) |
NotebookID |
Project(ProjectID,ProjectName,NotebookID,TechnicianID) |
ProjectID |
1:N:M 经理管理项目与工程师的关系
说明:
- 一名经理手下的一名工程师可能参与多个项目
- 一名经理管理的一个项目可能会有多名工程师
- 做某一个项目的一名工程师只会有一名经理
可以转换成以下模式:
关系模型 |
主键 |
Engineer(EngineerID,EngineerName) |
EngineerID |
Manager(ManagerID,ManagerName) |
ManagerID |
Project(ProjectID,ProjectName) |
ProjectID |
Manages(EngineerID,ProjectID,ManagerID) |
EngineerID,ProjectID |
可以转换成以下模式:
关系模型 |
主键 |
仓库(仓库号,仓库名名,地址) |
仓库号 |
商店(商店号,商店名) |
商店号 |
商品(商品号,商品名) |
商品号 |
进货(商店号,商品号,仓库号,日期,数量) |
商店号,商品号,仓库号 |
- 规范化关系模型表格
仅有好的RDBMS并不足以避免数据冗余,必须在数据库的设计中创建好的表结构
范式是具有最小冗余的表结构。这些范式是:
- a. 第一范式(1st NF -First Normal Fromate)
- b. 第二范式(2nd NF-Second Normal Fromate)
- c. 第三范式(3rd NF- Third Normal Fromate)
- 1. 第一范式 (lNF)
|
|
- 2. 第二范式(2NF)
例如: 表关系虽满足lNF,但不满足2NF, 原因:因为它的非主属性不完全依赖于由教师代码和课题代码组成的主关键字。 姓名,职称 部分依赖于 教师代码 研究课题名称 部分依赖于 研究课题号 导致问题: 这种关系会引起数据冗余 更新异常,当要插入新的研究课题数据时,往往缺少相应的教师代码,以致无法插入 当删除某位教师的信息时,常会引起丢失有关研究课题信息。 解决办法: 将一个非2NF的关系模式分解为多个2NF的关系模式。 |
|||||
表被分解为如下三个关系: |
|||||
·教师表:教师代码、姓名、职称; ·课题表:研究课题号、研究课题名; ·教师与课题表:教师代码、研究课题号。 |
|||||
这些关系都符合2NF要求。 |
|||||
- 3. 第三范式(3NF)
如果一个关系满足2NF,并且除了主键以外的其他列都不传递依赖于主键列,则满足第三范式(3NF)
例如:
表产品关系属第二范式,但不是第三范式。
原因:由于生产厂名依赖于产品代码 (产品代码惟一确定该产品的生产厂家),生产厂地址又依赖于厂名,因而,生产厂地址传递依赖于产品代码。
导致问题:
存在数据冗余
更新异常问题
当删除一个产品记录时,可能造成所连带的唯一一条生产厂商信息连带删除掉,造成数据丢失。
解决办法:
消除传递依赖关系的办法,是将原关系分解: |
|
产品表:产品代码、产品名、生产厂名; 生产厂表 :生产厂名、生产厂地址。 3NF消除了插入、删除异常及数据冗余、修改复杂等问题,已经是比较规范的关系 |
- 4. 规范化和性能
范式可以避免数据冗余,减少数据库的空间,减轻维护数据完整性的麻烦,但是操作难,因为需要联系多个表才能得到所需要数据,而且越高范式性能就会越差。要权衡是否使用更高范式是比较麻烦。
为满足某种商业目标,数据库性能比规范化数据库更重要
通过在给定的表中添加额外的字段,以大量减少需要从中搜索信息所需的时间
通过在给定的表中插入计算列(如成绩总分),以方便查询
进行规范化的同时,还需要综合考虑数据库的性能。
- 5. 案例
假设某建筑公司要设计一个数据库。公司的业务规
则概括说明如下:
- 公司承担多个工程项目,每一项工程有:工程号、工程名称、施工人员等
- 公司有多名职工,每一名职工有:职工号、姓名、性别、职务(工程师、技术员)等
- 公司按照工时和小时工资率支付工资,小时工资率由职工的职务决定(例如,技术员的小时工资率与工程师不同)
- 公司定期制定一个工资报表和项目工时表,如图
工资报表
工程号 |
工程名称 |
职工号 |
姓名 |
职务 |
小时工资率 |
工时 |
实发工资 |
A1 |
花园大厦 |
1001 |
齐光明 |
工程师 |
65 |
13 |
845.00 |
1002 |
李思岐 |
技术员 |
60 |
16 |
960.00 |
||
1004 |
葛宇宏 |
律师 |
60 |
19 |
1140.00 |
||
小计 |
2945.00 |
||||||
A2 |
立交桥 |
1001 |
齐光明 |
工程师 |
65 |
15 |
975.00 |
1003 |
鞠明亮 |
工人 |
55 |
17 |
935.00 |
||
小计 |
1910.00 |
||||||
A3 |
临江饭店 |
1002 |
李思岐 |
技术员 |
60 |
18 |
1080.00 |
1004 |
葛宇洪 |
技术员 |
60 |
14 |
840.00 |
||
小计 |
1920.00 |
项目工时表
工程号 |
工程名称 |
职工号 |
姓名 |
职务 |
小时工资率 |
工时 |
A1 |
花园大厦 |
1001 |
齐光明 |
工程师 |
65 |
13 |
A1 |
花园大厦 |
1002 |
李思岐 |
技术员 |
60 |
16 |
A1 |
花园大厦 |
1001 |
齐光明 |
工程师 |
65 |
13 |
A1 |
花园大厦 |
1003 |
鞠明亮 |
工人 |
55 |
17 |
A3 |
临江饭店 |
1002 |
李思岐 |
技术员 |
60 |
18 |
A3 |
临江饭店 |
1004 |
葛宇洪 |
技术员 |
60 |
14 |
表中包含大量的冗余,可能会导致数据异常:
- 更新异常------------ 例如,修改职工号=1001的职务,则必须修改所有职工号=1001的行
- 添加异常------------ 若要增加一个新的职工时,首先必须给这名职工分配一个工程。或者为了添加一名新职工的数据,先给这名职工分配一个虚拟的工程。(因为主关键字不能为空)
- 删除异常------------ 例如,1001号职工要辞职,则必须删除所有职工号=1001的数据行。这样的删除操作,很可能丢失了其它有用的数据
采用这种方法设计表的结构,虽然很容易产生工资报表,但是每当一名职工分配一个工程时,都要重复输入大量的数据。这种重复的输入操作,很可能导致数据的不一致性。
应用规范化设计
一张表描述了多件事情,如图
三、总结
- 数据库设计必要性
- 数据库在软件开发中的生命周期及各阶段任务
- 数据库设计步骤
- 1. 在需求分析阶段,设计数据库的一般步骤为:
- 1. 收集信息
- 2. 标识对象
- 3. 标识每个对象的属性
- 4. 标识对象之间的关系
- 2. 在概要设计阶段和详细设计阶段,设计数据库的步骤为:
- 1. 绘制E-R图
- 2. 将E-R图转换为表格
- 3. 应用三大范式规范化表格
- 3. 为了设计结构良好的数据库,需要遵守一些专门的规则,称为数据库的设计范式 。
- 1. 第一范式(1NF)的目标:确保每列的原子性。
- 2. 第二范式(2NF)的目标:确保表中的每列,都和主键相关
- 3. 第三范式(3NF)的目标:确保每列都和主键列直接相关,而不是间接相关
- 4. 规范化和性能