数据库设计规范
数据库设计的重要性
为什么需要设计数据库?
当数据库比较复杂的时候, 我们就需要对数据库进行设计, 否则会带来以下一些问题:
- 数据冗余, 浪费空间
- 数据库插入和删除都会比较麻烦
- 程序的性能差
而一个良好的数据库设计会为我们带来以下一些好处:
- 节省内存空间
- 保证数据可的完整性
- 方便系统的开发
在软件开发中, 数据库设计分为以下几个步骤
分析需求: 分析业务和需要处理的数据库需求
概要设计: 设计关系图(E-R 图)
数据库设计三大范式
为什么需要数据规范化?
数据规范化是为了避免如下一些问题:
- 避免信息重复
- 避免更新异常
- 避免插入异常
- 避免删除异常
什么是数据库三大范式?
目前关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。
满足最低要求的范式是第一范式(1NF), 在第一范式的基础上进一步满足更多规范要求的称为第二范式(2NF),其余范式以次类推。一般来说,数据库只需满足第三范式(3NF)就行了, 这也就是我们要讲的三大范式。
第一范式(1NF): 要求数据库的每一列都是不可分割的原子数据项。
举例说明:
学号 | 姓名 | 性别 | 家庭信息 | 学校信息 |
---|---|---|---|---|
20220001 | 高启强 | 男 | 三口人, 广东 | 专科, 大三 |
20220002 | 孟钰 | 女 | 三口人, 北京 | 本科, 大二 |
20220003 | 徐江 | 男 | 两口人, 上海 | 硕士, 研三 |
在上面表格中, "家庭信息"和"学校信息"并不满足原子性的要求, 也就是说不满足第一范式, 调整如下:
学号 | 姓名 | 性别 | 家庭人口 | 户籍 | 学历 | 年级 |
---|---|---|---|---|---|---|
20220001 | 高启强 | 男 | 三口人 | 广东 | 专科 | 大三 |
20220002 | 孟钰 | 女 | 三口人 | 北京 | 本科 | 大二 |
20220003 | 徐江 | 男 | 两口人 | 上海 | 硕士 | 研三 |
第二范式(2NF): 在第一范式(1NF)的基础上,非属性码的属性必须完全依赖于主码。(在1NF基础上消除非属性码的属性对主码的部分函数依赖)
上面定义中的非属性码我们可以理解为除去主键之外的其他字段, 主码可以理解为主键, 简单说来说: 第二范式在满足第一范式的基础之上, 要求一张表只做一件事情
举例说明: 有如下一张表, 由于在同一个订单中可能包含不同的产品, 因此主键必须是"订单号"和"产品号"联合组成
订单号 | 产品号 | 产品数量 | 产品折扣 | 产品价格 | 订单金额 | 订单时间 |
---|---|---|---|---|---|---|
2008003 | 205 | 100 | 0.9 | 8.9 | 2087 | 20220103 |
2008003 | 206 | 200 | 0.8 | 9.9 | 2087 | 20220103 |
2008005 | 207 | 200 | 0.75 | 10 | 2000 | 20221011 |
上面表格中联合主键是由订单号和产品号组成, 但是可以发现产品数量、产品折扣、产品价格都是与主键订单号和产品号相关的(完全依赖); 而订单金额和订单时间只与订单号相关(部分依赖); 因此上面表就不满足第二范式, 需要对上面的表进行拆分, 拆分如下:
订单号 | 产品号 | 产品数量 | 产品折扣 | 产品价格 |
---|---|---|---|---|
2008003 | 205 | 100 | 0.9 | 8.9 |
2008003 | 206 | 200 | 0.8 | 9.9 |
2008005 | 207 | 200 | 0.75 | 10 |
订单号 | 订单金额 | 订单时间 |
---|---|---|
2008003 | 2087 | 20220103 |
2008003 | 2087 | 20220103 |
2008005 | 2000 | 20221011 |
第三范式(3NF): 在第二范式基础上, 任何非主属性都不依赖于其他非主属性(在2NF基础上,消除传递依赖)。
第三范式需要确保数据表中每一项数据都和主键直接相关, 而不能间接相关
举例说明:
学号 | 姓名 | 性别 | 家庭人口 | 班主任姓名 | 班主任性别 | 班主任年龄 |
---|---|---|---|---|---|---|
20220001 | 高启强 | 男 | 三口人 | 高明远 | 男 | 40 |
20220002 | 孟钰 | 女 | 三口人 | 高赫 | 男 | 30 |
20220003 | 徐江 | 男 | 两口人 | 孙明 | 男 | 20 |
上表中所有属性都完全依赖于主键学号, 满足第二范式; 但是班主任性别和班主任年龄是直接依赖于班主任姓名的, 而不是直接依赖于主键学号, 所以调整如下:
学号 | 姓名 | 性别 | 家庭人口 | 班主任姓名 |
---|---|---|---|---|
20220001 | 高启强 | 男 | 三口人 | 高明远 |
20220002 | 孟钰 | 女 | 三口人 | 高赫 |
20220003 | 徐江 | 男 | 两口人 | 孙明 |
班主任姓名 | 班主任性别 | 班主任年龄 |
---|---|---|
高明远 | 男 | 40 |
高赫 | 男 | 30 |
孙明 | 男 | 20 |
规范性和性能问题:
其实按照三大范式设计出来的数据表并不一定是最合理的, 甚至会影响性能, 阿里开发手册中就明确要求关联查询到表不能超过三张表, 而按照三大范式设计出来的表很容易就超过三张
因此考虑到商业化的需求时, 数据库的性能更加重要, 我们会故意给某些表增加一些冗余字段(从多表查询变为单表查询); 不过在追求性能时, 我们还是需要适当的考虑一下规范性