温习一下关系型数据库设计,其中最重要的就是理解三大范式,至于ER图,如果心中有谱,画在纸上也成。在网上找到一遍实用的文章,见:https://my.oschina.net/u/4414412/blog/3257987。内容部分摘录如下:
数据库设计是什么?
数据库设计是根据需求文档的描述,将需求转成数据库的存储结构的过程。
数据库设计要尽量符合数据库设计的三大范式原则——目标是解决数据的冗余问题。
那什么又是冗余?我从知乎上找了个示例:全文见:https://www.zhihu.com/question/24696366/answer/29189700
如上:你会看到好多个“王强”,好多个“经济系”,这样很多重复的数据,这就称之为冗余。而以下要学习的范式,就是要解决上述存在的问题。
(关系模式设计中可能会出现以下几个问题:数据冗余、数据修改不一致、数据插入异常、数据删除异常,所以提出范式的要求,目的就是最低限度地冗余,避免插入、删除、修改异常。)
遵循“三大范式”规则(良好示例)
说明:为了建立冗余较小、结构合理的数据库,设计数据库时必须遵循一定的规则。在关系型数据库中这种规则就称为范式。范式是符合某一种设计要求的总结。要想设计一个结构合理的关系型数据库,必须满足一定的范式。
第一范式 (确保每列保持原子性)
第一范式是最基本的范式。如果数据库表中的所有字段值都是不可分解的原子值,就说明该数据库表满足了第一范式。
第一范式的合理遵循需要根据系统的实际需求来定。比如某些数据库系统中需要用到 “地址” 这个属性,本来直接将 “地址” 属性设计成一个数据库表的字段就行。但是如果系统经常会访问 “地址” 属性中的 “城市” 部分,那么就非要将 “地址” 这个属性重新拆分为省份、城市、详细地址等多个部分进行存储,这样在对地址中某一部分操作的时候将非常方便。这样设计才算满足了数据库的第一范式,如下表所示。
上表所示的用户信息遵循了第一范式的要求,这样在对用户使用城市进行分类的时候就非常方便,也提高了数据库的性能。
第二范式 (确保表中的每列都和主键相关)
非主键列必须依赖主键列存在。
第二范式在第一范式的基础之上更进一层。第二范式需要确保数据库表中的每一列都和主键相关,而不能只与主键的某一部分相关(主要针对联合主键而言)。也就是说在一个数据库表中,一个表中只能保存一种数据,不可以把多种数据保存在同一张数据库表中。
比如要设计一个订单信息表,因为订单中可能会有多种商品,所以要将订单编号和商品编号作为数据库表的联合主键,如下表所示。
订单信息表
这样就产生一个问题:这个表中是以订单编号和商品编号作为联合主键。这样在该表中商品名称、单位、商品价格等信息不与该表的主键相关,而仅仅是与商品编号相关。所以在这里违反了第二范式的设计原则。
而如果把这个订单信息表进行拆分,把商品信息分离到另一个表中,把订单项目表也分离到另一个表中,就非常完美了。如下所示。
这样设计,在很大程度上减小了数据库的冗余。如果要获取订单的商品信息,使用商品编号到商品信息表中查询即可。
第三范式 (确保每列都和主键列直接相关,而不是间接相关 - 在 2NF 基础上消除传递依赖)
第三范式需要确保数据表中的每一列数据都和主键直接相关,而不能间接相关。比如在设计一个订单数据表的时候,可以将客户编号作为一个外键和订单表建立相应的关系。而不可以在订单表中添加关于客户其它信息(比如姓名、所属公司等)的字段。如下面这两个表所示的设计就是一个满足第三范式的数据库表。
这样在查询订单信息的时候,就可以使用客户编号来引用客户信息表中的记录,也不必在订单信息表中多次输入客户信息的内容,减小了数据冗余。
三大范式只是一般设计数据库的基本理念,可以建立冗余较小、结构合理的数据库。如果有特殊情况,当然要特殊对待,数据库设计最重要的是看需求跟性能,需求 > 性能 > 表结构(范式)。所以不能一味的去追求范式建立数据库。
示例:冗余数据与需求/性能的平衡
如上,在数据库设计中,遵循范式,目的就是为了避免数据的冗余,但是在实际的数据库设计中,并不完全一定要按三大范式去执行,而是追求一种平衡,这要如何理解呢?此文有举例如下:
性能的要求出现的冗余数据
很多系统都要记录日志。而日志里面,必须要包括用户的信息。如果严格按照三大方式。日志的用户信息必须是从用户表中获得,日志每天都会出现巨量的数据。如果关联用户表查询,整理日志时会导致用户表的访问大大被拖慢(理解补充:导致性能下降)。
所以,我们会将用户的信息直接写在日志表里面。在日志表中写用户的的信息,明显违反了第二范式,基于查询的性能的需要,一般日志表的用户信息是冗余。
(理解补充:满足需求优先)
示例:业务逻辑的要求出现的冗余数据
我们在订单中有一个商品的价格、商品名字。而这个商品的价格直接就是订单的字段。并不是商品表里面商品的价格。明显违反了第三范式.
但业务上,由于订单的商品价格不能随着商家修改了商品价格而修改。所以像这种需求下,必须要给订单表一个冗余的商品价格字段。
(理解补充:满足业务逻辑优先。例如我在京东上买东西,可以查看三个月或更长时间的订单信息,因此订单的商品价格,应当是下单时那个价格,而不是随着时间变化,有调整的商品价格。)
(我发现这两个示例,较适合后台管理,是针对已经发生的行为做的数据记录,便于管理者/用户查询之用,也方便删除,这些操作不会影响其他的表(如商品表,大量在前台展示/访问),这种冗余设计是很有意义的。因此,在数据库的设计上,大的宏观/顶层方面,是要遵守范式,在此之内,则具体情况具体对待。)
再次摘录:
三大范式只是一般设计数据库的基本理念,可以建立冗余较小、结构合理的数据库。如果有特殊情况,当然要特殊对待,数据库设计最重要的是看需求跟性能,需求 > 性能 > 表结构(范式)。所以不能一味的去追求范式建立数据库。
这就是数据库设计,宏观层面的指导原则。
由需求确定的数据库表与表的从属关系
表与表之间的关系包括有:一对一、一对多/多对一、多对多。
关系数据库是不能直接支持多对多的业务关系的,如果出现多对多必须要拆分一个中间表(见下面的示例表),原因是数据库里面的字段不能存储一个集合数据。
(这个图,似乎点儿多对多的意思~但细品,却不是这样。)
数据库表与表的关系,就是也需求描述的从属关系。是由需求决定的。先确定需求,再讨论表之间的关系。
示例:
遵循范式设计:
(严格按照范式,设计成三个表,多对多关系——其中第三个表存储第一和第二个表之间的关系。)
以实际需求为主的设计:
(按实际需求,设计成两个表,看上去是一对多关系,然本质上还是多对多,只是teacher_id这个对应的外键字段,存储了多个值。我发现这是一个值得学习的技巧和良好示例,因为获取数据可用SQL语句的select结合in来解决。)
文章中的总结:
为什么需要三大范式,避免数据的冗余,导致数据的异常。
数据库设计总体上要符合三大范式,但是基于业务需求和性能要求,有时候可以有少许的冗余。数据设计冗余,设计者必须要说明原因 (项目需求需要)
ER数据库关系图的设计与示例
数据库设计的流程上,我们通常根据需求,画出数据的 ER 图(Entity Relational)。然后在通过 ER 图生成数据库的建库脚本。
ER 图,所谓的 ER 图就是数据库关系图。
进一步,数据库设计,就是通过 ER 图,根据需求给数据库建立表结构!
示例1——需求:设计一个学生成绩管理系统
- 首先有学生,学生必须包括登录、禁用功能
- 基于安全性的考虑,学生的身份信息要单独存储
- 一个学生有多门成绩
- 一个学生可以有多个老师,一个老师也可以教多个学生
第一步:标识表,标识实体表。学生、学生身份、成绩、老师
第二步:标识字段
第三步:标识表与表之间的关系
用ER设计图来表示,如下:
示例2——CRM 系统的数据库设计
客户调研
客户人员是一个不懂软件设计的人,它希望有一个可以做管理系统来管理他的员工。
描述如下:
系统的需求调研: 1. 每个销售人员只能查看自己的客户. (销售不能互相看客户) 2. 客户是公司,有多个联系人 (客户主体公司) 3. 销售可以指定客户给另一个销售人员跟进 (销售人员可以转移客户给另外销售) 4. 销售人员离职时,可以禁用不让登录 5. 管理员可以修改销售人员的密码 (后台管理人员可以管理所有信息) 6. 销售人员可以设置重点跟进客户,并且可以说明重点跟进客户的原因. 7. 销售人员可以多次跟进同一个客户(骚扰) |
系统功能列表(需求文档的核心部分)
功能列表给到客户人员。给到开发人员,跟进需求文档设计数据库。
前端功能(销售人员的功能) | 1. 客户管理 |
2. 联系人管理 | |
3. 转移客户 | |
4. 跟进客户 | |
5. 标记重点客户 | |
后台管理(管理员管理 RBAC) | 1. 客户管理 (全局) |
2. 联系人管理(全局) | |
3. 管理员管理 | |
4. 角色管理 | |
5. 权限管理 |
(需求排第一)
数据库设计
根据功能列表与客户调研报告(需求文档),设计数据数据库。
第一步:RBAC 系统的设计
Role Based Access Control (基于角色的权限控制系统);就是根据不同的用户,根据用于所属的角色不同而登录的界面就不同。
需求:一个管理员只有一个角色(单角色的设计),一个角色可以有多个管理员。
一个就是可以有多个权限,一个权限也可以有在多个角色角色。
(理解补充:RBAC系统是通用的模块。例如很多年前的ASP.NET,就自带有此功能,最近接触django,也是默认就提供这样的后台管理功能。)
第二步:业务系统的设计(CRM)
需求:
- 一个销售(用户),只能查看自己的客户
- 客户是公司,有多个联系人 (客户主体公司)
- 销售人员可以设置重点跟进客户,并且可以说明重点跟进客户的原因.
- 销售人员离职时,可以禁用不让登录
- 销售人员可以多次跟进同一个客户(骚扰)
- 销售可以指定客户给另一个销售人员跟进
数据设计工具与软件
文章示例是用PowerDesigner专业软件,可以制作ER图和导出sql来直接创建数据结构。
但我似乎用不着这么专业的软件,只是要画ER图的话,我用ProcessOn就好。