数据库设计-三范式
概念
关系型数据库设计的一种标准化过程,目的是消除冗余数据,提高数据存储的效率和数据的完整性。
关系
三大范式是一级一级依赖的,第二范式建立在第一范式上,第三范式建立在一第二范式上。
特点
第一范式(1NF):列不可再分,其特点是每一个属性必须是原子性的,且每一列都是同一类型,换言之,在一个列中,不可存在多个属性值,如订单表中,订单号只能是一个且唯一;
第二范式(2NF):主键确保行数据的唯一性,是建立在第一范式的基础上,消除部分依赖,使每个非主键的属性与主键存在完全的依赖性。
第三范式(3NF):表的非主属性不能依赖于其他表的非主属性,也就是说每一张表的都是一个类型的全描述,如商品名称属性,只能在商品表中,而不是存储在订单表中,消除传递依赖,确保非主属性只与主键直接关联,而不是通过其他属性进行关联。
总结
- 1NF消除重复,确保数据的原子性;
- 2NF强调了主键的依赖性;
- 3NF强调了数据的完整性,避免了传递依赖;
- 三范式表述了我们设计数据库的过程中的合理性及可操作性,同时要求保证数据完整性;
- 三范式不是固定的,需要结合现场业务来考虑,过度的遵从有时会降低查询性能,所以有的时候数据该冗余还得冗余。
数据库三大范式
我们为了减少数据库中冗余,避免操作异常,造成数据库的浪费和报错,这时我们在设计数据库时就要按照一定的规则来避免这种以上这种情况,这种规则叫做范式。范式简单来说就是设计数据库的一些规范。
1-满足这些规则的数据库,在呈现上会显得更加的简洁和结构条理清晰。
2-在插入(insert),删除(delete),更新(update)操作时不会发生异常。
3-如果不满足这些规则时,每人都有不同的显现方式会在数据库的形式上会显得乱七八糟,结构混乱,给数据库的编程人员造成很大的麻烦,可能储存了大量的冗余信息。
第一范式(1NF)
定义:数据库表中的字段都是单一属性
——字段不可再分(列唯一)
——同一个列中不能有多个值(值唯一)
这些单一属性由基本类型构成,包括:整数,实数,字符型,逻辑型,日期型和其他类型
第二范式(2NF)
定义:在满足第一范式的前提下,数据库中的每张表均有主键。
1-单字段主键
2-联合主键(由两个或者两个以上的字段共同组成的主键):不能存在联合主键中某个主键字段决定非主键字段的情况
该表不满足第二范式,因为客户和开户银行为联合主键,客户决定客户电话,开户银行决定开户行地址,违反了联合主键字段决定非主键字段,做法就是将该表拆分为客户表和银行表即可。
第三范式(3NF)
定义:在满足第二范式的前提下,数据表的主键字段不存在传递依赖关系。即:非主键字段不能决定其他的非主键字段。
该表“工号”为主键,“部门”决定“部门电话”,“部门”决定“部门主管”,则存在非主键字段决定其它的非主键字段,不符合第三范式。符合范式,做法将其拆分为员工表和部门表。
字节2面:为了性能,你会违反数据库三范式吗?
三范式是数据库设计中最基本的三个规范,那么,三范式到底是什么?在实际开发中,为了性能,我们需要违反三范式吗?这篇文章,我们一起来聊一聊。
第一范式要求数据库中的每个表格的每个字段(列)都具有原子性,即字段中的值不可再分割。换句话说,每个字段只能存储一个单一的值,不能包含集合、数组或重复的组,即确保每列保持原子性。
如下示例: 假设有一个学生表 Student,结构如下:
在这个表中,电话号码字段包含多个号码,违反了1NF的原子性要求。为了满足1NF,需要将电话号码拆分为单独的记录或创建一个新的表。
满足 1NF后的设计:
学生表 Student
电话表 Phone
第二范式要求满足第一范式,并且消除表中的部分依赖,即非主键字段必须完全依赖于主键,而不是仅依赖于主键的一部分,即确保表中的每列都和主键相关。这主要适用于复合主键的情况。
如下示例:假设有一个订单详情表 OrderDetail,结构如下:
在上述表中,主键是复合主键 (订单ID, 商品ID)。商品名称和单价只依赖于复合主键中的商品ID,而不是整个主键,存在部分依赖,违反了2NF。
满足 2NF后的设计:
订单详情表 OrderDetail
商品表 Product
第三范式要求满足第二范式,并且消除表中的传递依赖,即非主键字段不应依赖于其他非主键字段。换句话说,所有非主键字段必须直接依赖于主键,而不是通过其他非主键字段间接依赖,或者说:确保每列都和主键列直接相关,而不是间接相关。
如下示例:假设有一张员工表 Employee,结构如下:
在这张表中,部门名称依赖于部门ID,而部门ID依赖于主键员工ID,形成了传递依赖,违反了3NF。
满足3NF后的设计:
员工表 Employee
部门表 Department
通过将部门信息移到单独的表中,消除了传递依赖,使得数据库结构符合第三范式。
最后,我们总结一下数据库设计的三大范式:
- 第一范式(1NF): 确保每个字段的值都是原子性的,不可再分。
- 第二范式(2NF): 在满足 1NF的基础上,消除部分依赖,确保非主键字段完全依赖于主键。
- 第三范式(3NF): 在满足 2NF的基础上,消除传递依赖,确保非主键字段直接依赖于主键。
在实际工作中,尽管遵循数据库的三大范式(1NF、2NF、3NF)有助于提高数据的一致性和减少冗余,但在某些情况下,为了满足性能、简化设计或特定业务需求,我们可能需要违反这些范式。
下面列举了一些常见的破坏三范式的原因及对应的示例。
在高并发、大数据量的应用场景中,严格遵循三范式可能导致频繁的联表查询,增加查询时间和系统负载。为了提高查询性能,设计者可能会通过冗余数据来减少联表操作。
假设有一个电商系统,包含订单表 Orders 和用户表 Users。在严格 3NF设计中,订单表只存储 用户ID,需要通过联表查询获取用户的详细信息。
但是,为了查询性能,我们通常会在订单表中冗余存储 用户姓名 和 用户地址等信息,因此,查询订单信息时无需联表查询 Users 表,从而提升查询速度。
破坏 3NF后的设计:
严格规范化可能导致数据库结构过于复杂,增加开发和维护的难度,为了简化查询逻辑和减少开发复杂度,我们也可能会选择适当的冗余。
比如,在内容管理系统(CMS)中,文章表 Articles 和分类表 Categories 通常是独立的,如果频繁需要显示文章所属的分类名称,联表查询可能增加复杂性。因此,通过在 Articles 表中直接存储 分类名称,可以简化前端展示逻辑,减少开发工作量。
破坏 3NF后的设计:
在数据仓库和报表系统中,通常需要快速读取和聚合大量数据。为了优化查询性能和数据分析,可能会采用冗余的数据结构,甚至使用星型或雪花型模式,这些模式并不完全符合三范式。
在销售数据仓库中,为了快速生成销售报表,可能会创建一个包含维度信息的事实表。
破坏 3NF后的设计:
在事实表中直接存储 产品名称 和 类别,避免了需要联表查询维度表,提高了报表生成的效率。
在某些业务场景下,可能需要快速响应特定的查询或操作,这时通过适当的冗余设计可以满足业务需求。
比如,在实时交易系统中,为了快速计算用户的账户余额,可能会在用户表中直接存储当前余额,而不是每次交易时都计算。
破坏 3NF后的设计:
在交易记录表中存储每笔交易的增减,但直接在用户表中维护 当前余额,避免了每次查询时的复杂计算。
在某些应用中,读操作远多于写操作。为了优化读性能,可能会通过数据冗余来提升查询速度,而接受在数据写入时需要额外的维护工作。
社交媒体平台中,用户的好友数常被展示在用户主页上。如果每次请求都计算好友数量,效率低下。可以在用户表中维护一个 好友数 字段。
破坏3NF后的设计:
通过在 Users 表中冗余存储 好友数,可以快速展示,无需实时计算。
在快速发展的产品或初创企业中,数据库设计可能需要频繁调整。过度规范化可能导致设计不够灵活,影响迭代速度。适当的冗余设计可以提高开发的灵活性和速度。
一个初创电商平台在初期快速上线,数据库设计时为了简化开发,可能会将用户的收货地址直接存储在订单表中,而不是单独创建地址表。
破坏3NF后的设计:
这样设计可以快速上线,后续根据需求再进行规范化和优化。
有时,过度规范化可能使数据库结构变得复杂,难以理解和维护。适度的冗余可以降低设计的复杂性,提高团队对数据库结构的理解和沟通效率。
在一个学校管理系统中,如果将学生的班级信息独立为多个表,可能增加理解难度。为了简化设计,可以在学生表中直接存储班级名称。
破坏3NF后的设计:
通过在学生表中直接存储 班级名称 和 班主任,减少了表的数量,简化了设计。
本文,我们分析了数据库的三范式以及对应的示例,它是数据库设计的基本规范。但是,在实际工作中,为了满足性能、简化设计、快速迭代或特定业务需求,我们很多时候并不会严格地遵守三范式。
所以说,架构很多时候都是业务需求、数据一致性、系统性能、开发效率等各种因素权衡的结果,我们需要根据具体应用场景做出合理的设计选择。
本文作者及来源:Renderbus瑞云渲染农场https://www.renderbus.com
文章为作者独立观点不代本网立场,未经允许不得转载。