1.数据库的设计
1.1.定义
数据库设计指的是将应用中涉及的数据实体及这些数据实体 之间的关系,进行规划和结构化的过程。
1.2.影响数据库系统效率的因素
数据库中创建的数据结构种类,以及在数据实体之间建立的关系
好的设计:效率高,便于进一步扩展,使应用程序的开发变得容易
糟糕的设计:效率低下,更新和检索数据时会出现许多问题
1.3.设计的步骤
一般在项目开发需要经过:需求分析、概要设计、详细设计、代码编写、运行测试和部署上线这几个阶段,而数据设计在这几个阶段主要做的事,如下:(当然上线后有时也会出现改需求,动代码动数据库 )
1.3.1需求分析阶段
分析客户业务和数据处理需求
1.3.2概要设计阶段
绘制数据库的E-R图,用于在项目团队内部、设计人员和客户之间的沟通,确认需求信息的正确性和完整性。
1.3.3详细设计阶段
将E-R 图转换为多张表,进行逻辑设计,确认各表的主外键,并应用数据库设计的三大范式进行审核。经项目开会讨论确定后,根据项目的技术实现、团队开发能力进行项目的成本预算,选择具体的 数据库进行物理实现,之后就是开发应用程序
1.3.4注意
在需求分析阶段的重点是调查、收集并分析客户业务的数据需求、处理需求 、安全性与完整性需求。
常用的需求调研方法:在客户的公司跟班实习、组织召开调查会、邀请专人介绍、设计调查表并请用户填写和查阅与业务相关的数据记录等。
常用的需求分析方法:调查客户的公司组织情况、各部门的业务需求情况、协助客户分析系统的各种业务需求和确定新系统的边界。
1.3.5在进行数据库分析时可参考的基本步骤
收集信息:创建数据库之前,必须充分理解数据库需要完成的任务和功能,了解数据库需要存储哪些数据、实现哪些功能
标识实体:收集信息后,标识数据库要管理的关键对象或实体。(实体一般是名词,一个实体只描述一件事情,不能出现含义相同的实体,而且实体可以是有形的事物(如人或产品),也可以是无形的事物(如部门,时间)
标识每个实体需要存储的详细信息: 将数据库中的主要实体表示为表的候选实体以后,就要标识每个实体存储的详细信息,也称为该实体的属性,这些属性将组成表中列。
注意:在进行实体属性分解是,含义相同的成员信息不能重复出现(如联系方式与电话)每个实体对应一个表,实体中的每个属性对应表中的每一列
标识实体之间的关系: 关系型数据库的一个强大功能,可以关联数据库中各个项目的相关信息。不同类型的信息可以单独存储,当需要的时候,数据库引擎还可以根据需要将数据组合起来。 在设计过程中,要标识实体之间的关系,首先需要分析数据库表,确定这些表在逻辑上是如何相关的,然后添加关系列建立起表之间的连接,总的来说就是了解需求分析信息确定需要哪些表,在确定各个表中需要哪些列,以及各个表之间的关系
1.3.6实现思路
收集信息:确定客户需要做什么之后,收集一切相关的信息,尽量不遗漏任何信息
标识实体(确定表):原则是实体一般是名词,一个实体只能描述一件事,不能重复出现含义相同的实体
标识每个实体属性(确定列):确定每个实体需要存储哪些信息
标识各个实体之间的联系(确定表之间的关系)
1.4.E-R 图
E-R 图(Entity-Relationship)也称为实体-关系图 ,用于和项目团队的其他成员及客户沟通,讨论数据库设计是否满足客户的业务和数据处理需求,主要由一些含有特殊含义的图形符号构成
矩形表示实体 ,椭圆表示属性 , 菱形表示联系集 ,直接用来连接属性与实体集 , 或者实体集与联系集
1.4.1实体
指现实世界中具有区分其他事物的特征或属性并与其他事物有联系事物。实体一般是名词,对应表中的一行数据
1.4.2属性
指实体的特征 , 属性对应表中的列
1.4.3联系
指两个或多个实体之间的关联关系
实体用矩形表示,一般是名词
属性用椭圆形表示,一般也是名词
联系用菱形表示,一般是动词
1.4.4映射基数
表示通过联系与该实体关联的其他实体的个数。
1.4.5实体集之间的关系
对于实体集X与Y之间的关系有以下四个:一对一、一对多、多对一、多对多
一对一:X中的一个实体最多与Y中的一个实体关联,并且Y中的一个实体最多与X中的一个实体关联。
一对多:X中的一个实体可以与Y中的任意数量的实体关联,Y中的一个实体最多与X中的一个实体关联
多对一:X中的一个实体最多与Y中的一个实体关联,Y中的一个实体可以与X中任意数量的实体关联
多对多:X中的一个实体可以与Y中的任意数量的实体关联,Y中的一个实体可以与X中任意数量的实体关联
1.4.6实体关系图
矩形表示实体
椭圆形表示属性
菱形表示联系集
直线用来连接属性与实体集,实体集与联系集,直线也可以是有方向的 (在末端有一个箭头),用来表示联系集的映射基数,箭头可以视为指向引用的实体。
主要就是三种方式:一对一( 1:1)、一对多(1:N)、多对多(M:N)
1.5.关系数据库模式
关系数据库模式是对关系数据库结构(或框架)的描述,一个关系通常对应一个表。
(关系模型: 指使用二维表的形式表示实体和实体间联系的数据模型)
关系模式 的表现形式有:R(U) 或 R(A,B)
其中,R表示关系名,U表示属性集合,A,B 代表U中的属性
1.5.1将E-R 图转换为关系模式的步骤
1.5.1.1将实体转化为关系模式的R(A,B…)形式
如上述的:供应商,商品
供应商(供应商编码,供应商名称,类型,联系方式、地址)
商品(商品编码,商品名称,类型,单价,数量)
1.5.1.2 建立实体间联系的转换(一对一,一对多,多对多)
当两个实体各自转化为 关系模式后,实体间联系的转换
一对一的转换:把任意实体的主键放到另一实体的关系模式中
一对多的转换:把联系数量为1的实体的主键,放到联系数量为N 的实体关系模式中
多对多的转换:把两个实体中的主键和联系属性放到另一个关系模式中,需要多生成一个关系模式中
上述也可以转换为: 下划线为主键,加粗为外键,考虑的是 一个商品有多个供应商
供应商(供应商编码,供应商名称,类型,联系方式、地址,商品编码)
商品(商品编码,商品名称,类型,单价,数量)
2. 数据库的设计规范
三大范式是 Mysql 数据库设计表结构所遵循的规范和指导方法,目的是为了减少冗余,建立结构合理的数据库,从而提高数据存储和使用的性能。
三大范式之间是具有依赖关系的,比如第二范式是在第一范式的基础上建设的、第三范式是在第二范式的基础上建设的。
当然 Mysql 数据库的范式不止三大范式,除了三大范式,还有巴斯-科德范式(BCNF)、第四范式(4NF)、第五范式(5NF,又称“完美范式")。
而本篇文章,我们只介绍范式中常用的三大范式。
虽然,遵循范式能使我们的数据库结构更合理,但是也不是一成不变的,偶尔我们也要学会在范式的基础,根据实际应用场景,作出相应的变通。
2.1了解主外键
2.1.1主键
能做主键的列必要满足非空唯一的特点。
只要满足非空唯一的任何列都可以做主键。
可以让表中一个有意义的列做主键,比如说学号,它既表示学生学号又作为表中的主键,因为这个列满足非空唯一的条件。
也可以找一个没有意义的列做主键,就是用来唯一标识一行记录的。
我们可以让多个列联合在一起做表中的主键,那么它就是联合主键,要求这几个列的值联合在一起是非空唯一。
2.1.2外键
表中的某一个列声明为外键列,一般这个外键列的值都会引用于另外一张表的主键列的值(有唯一约束的列就可以,不一定非要引用主键列)。
另外一张表的主键列中出现过的值都可以在外键列中使用,没有出现过的值,都不能使用。
外键列值也可以为空的,提前是这个外键列在表中不做主键,因为我们也可以把表中的外键列当做主键来使用(只有满足非空唯一的要求就可以)。
如果把B表中的联合主键的值引用到A表中做外键,因为是俩个列在B表中做联合主键,那么A表引用过来的时候也要把俩个列的值都引用过来,那么它们在A表中就会作为一个联合外键出现。
2.2.第一范式 - 1NF
遵循原子性。即,表中字段的数据,不可以再拆分。
先看一个不符合第一范式的表结构,如下:
员工编码 姓名 年龄
001 销售部小张 28
002 运营部小黄 25
003 技术部小高 22
在这一个表中的,姓名 字段下的数据是可以再进行拆分的,因此它不符合第一范式,那怎么样才符合第一范式呢?如下:
员工编码 部门 姓名 年龄
001 销售部 小张 28
002 运营部 小黄 25
003 技术部 小高 22
那是否遵循第一范式就一定是好的呢?如下:
员工编码 姓名 地址
001 小张 江西省南昌市东湖区
002 小黄 广东省佛山市禅城区
003 小高 湖北省武汉市新洲区
通过观察上述表结构,我们发现,地址是可以再进一步拆分的,比如:
员工编码 姓名 省 市 区
001 小张 江西省 南昌市 东湖区
002 小黄 广东省 佛山市 禅城区
003 小高 湖北省 武汉市 新洲区
虽然拆分后,看上去更符合第一范式了,但是如果项目就只需要我们输出一个完整地址呢?那明显是表在没拆分的时候会更好用。
所以范式只是给了我们一个参考,我们更多的是要根据项目实际情况设计表结构。
2.3.第二范式 - 2NF
在满足第一范式的情况下,遵循唯一性,消除部分依赖。即,表中任意一个主键或任意一组联合主键,可以确定除该主键外的所有的非主键值。
再通俗点讲就是,一个表只能描述一件事情。
我们用一个经典案例进行解析。
学号 姓名 年龄 课程名称 成绩 学分
001 小张 28 语文 90 3
001 小张 28 数学 90 2
002 小黄 25 语文 90 3
002 小黄 25 语文 90 3
003 小高 22 数学 90 2
我们先分析一下表结构。
假设学号是表中的唯一主键,那由学号就可以确定姓名和年龄了,但是却不能确定课程名称和成绩。
假设课程名称是表中的唯一主键,那由课程名称就可以确定学分了,但是却不能确定姓名、年龄和成绩。
虽然通过学号和课程名称的联合主键,可以确定除联合主键外的所有的非主键值,但是基于上述两个假设,也不符合第二范式的要求。
那我们应该如何调整表结构,让它能复合第二范式的要求呢?
我们可以基于上述的三种主键的可能,拆分成 3 张表,保证一张表只描述一件事情。
1. 学生表 - 学号做主键
学号 姓名 年龄
001 小张 28
002 小黄 25
003 小高 22
课程表 - 课程名称做主键
课程名称 学分
语文 3
数学 2
成绩表 - 学号和课程名称做联合主键
学号 课程名称 成绩
001 语文 90
001 数学 90
002 语文 90
002 语文 90
003 数学 90
这时候我们可能会想,为什么我们就要遵循第二范式呢?不遵循第二范式会造成什么样的后果呢?
2.3.1不遵循第二范式会造成的后果
2.3.1.1 造成整表的数据冗余。
如,学生表,可能我就只有2个学生,每个学生都有许多的信息,比如,年龄、性别、身高、住址…如果与课程信息放到同一张表中,可能每个学生有3门课程,那数据总条数就会变成6条了。但是通过拆分,学生表我们只需要存储 2 条学生信息,课程表只需要存储 3 条课程信息,成绩表就只需保留学号、课程名称和成绩字段。
2.3.1.2.更新数据不方便。
假设,课程的学分发生了变更,那我们就需要把整表关于该课程的学分都要更新一次,但如果我们拆分出课程表,那我们就只需要把课程表中的课程信息更新就行。
2.3.1.3 插入数据不方便或产生异常。
① 假设主键是学号或课程名称,我们新增了某个课程,需要把数据插入到表中,这时,可能只有部分人有选修这门课程,那我们插入数据的时候还要规定给哪些人插入对应的课程信息,同时可能由于成绩还没有,我们需要对成绩置空,后续有成绩后还得重新更新一遍。
② 假设主键是学号和课程名称的联合主键。同样也是新增了某课程,但是暂时没有人选修这门课,缺少了学号主键字段数据,会导致课程信息无法插入。
2.4. 第三范式 - 3NF
在满足第二范式的情况下,消除传递依赖。即,在任一主键都可以确定所有非主键字段值的情况下,不能存在某非主键字段 A 可以获取 某非主键字段 B。
仍然用一个经典例子来解析
学号 姓名 班级 班主任
001 小黄 一年级(1)班 高老师
这个表中,学号是主键,它可以唯一确定姓名、班级、班主任,符合了第二范式,但是在非主键字段中,我们也可以通过班级推导出该班级的班主任,所以它是不符合第三范式的。
那怎么设计表结构,才是符合第三范式的呢?
1. 学生表
学号 姓名 班级
001 小黄 一年级(1)班
班级表
班级 班主任
一年级(1)班 高老师
2.5.总结
通过把班级与班主任的映射关系另外做成一张映射表,我们就成功地消除了表中的传递依赖了。
不知道读者们有没有发现,以上所介绍的范式的最终目的都是为了减少我们的工作量呢?所以说,尽管范式是一种很好的指导规范,但在实际应用中,我们也不需要太局限在范式中,更多的是应该从项目中出发,设计出合理的表结构。
以下是本篇三范式的简单总结:
第一范式(1 NF):字段不可再拆分。
第二范式(2 NF):表中任意一个主键或任意一组联合主键,可以确定除该主键外的所有的非主键值。
第三范式(3 NF):在任一主键都可以确定所有非主键字段值的情况下,不能存在某非主键字段 A 可以获取 某非主键字段 B。
3.绘制数据库模型图
3.1好处
设计良好的数据库模型可以通过图形化的方式显示数据库存储的信息及表之间的关系,以确保数据库设计的准确、完整且有效。
3.2注意
在数据库模型图中体现实体的映射关系,上述 定义的 商品与供应商之间是一对多的关系,多的那一方会有一 的主键作为外键进行关联
一般来说,一对多的关系是一个表中的主键对应另一个表中的字段名与主键名相同。
在多对多关系中除了要将多对多种的两个实体各自转换为表外,一般要创建一个第三个表,将多对多的关系划分为两个一对多的关系,而这个表称为连接表,主要存放这两个表的主键,用来记录关系的每个匹配项或实例。
如:订单表和产品表间是多对多关系,这种关系可以通过与订单明细表建立两个一对多关系来定义,一个订单有多个产品,每个产品可以出现在多个订单中。