1
一个三线城市的国企码农,热爱技术,在这里和大家分享在国企搞技术的点点滴滴。欢迎大家关注我的微信公众号:果冻想

前言

每天开各种会议,这不刚刚结束的组织生活会的批评环节,我又收到了一条批评,说我技术分享不多,不够,没有有效起到传帮带的作用。好吧,以后就把这些日常的传帮带都总结起来,发到这里,作为一个记录,也以备组内小兄弟们后续翻阅查看。

这几天在整理数据库表的时候,看到之前的支撑方建的那些表,简直不忍直视,完全没有逻辑可言,反正就是一堆东西都放到一个表里,不知道大学数据库理论是怎么学习的。今天在和组内小兄弟们沟通时,就说起这个东西,正好涉及到数据库的三范式,就顺带总结下来。

数据库三范式

这个东西是一种关系型数据库设计理论理论原则,也不是说必须去遵守,只是说我们在进行数据库建模时,按着这个理论来执行,会更科学一点,会更合理一点,后续扩展性会更强一点;并且能在很大程度上消除数据冗余和数据依赖性,提高数据库的性能和数据一致性。

所以,这套理论有这种那种的优点,我们在进行关系型数据库建模时,也基本都是按照这个理论来执行的,至少按照这个来,做出来的东西不会太差。

三范式的定义:

第一范式(1NF):确保数据库中的每个列都是原子性的,即每个列都不可再分。

第二范式(2NF):在满足第一范式的基础上,确保数据库中的每个非主键列完全依赖于主键。

第三范式(3NF):在满足第二范式的基础上,确保数据库中的每个非主键列都不传递依赖于主键。

以上是三范式的定义,可能不是很好理解,下面通过具体的数据库建模实例来进行说明。

第一范式(1NF)

第一范式(1NF)要求的是列的原子性。这样讲可能不太好理解,现在有下面这样的一个地址表:

地址ID地址详情
202311212056485430000081内蒙古呼和浩特市新城区团结小区7号楼
202311231036360980000279内蒙古呼和浩特市赛罕区万达一区底商101

结合第一范式(1NF)的定义,很显然,地址详情这列包含的信息量很大,显然是可以拆分的。按照第一范式(1NF),我们进行以下拆分:

地址ID省/自治区地市地区小区名称楼栋门牌号
202311212056485430000081内蒙古呼和浩特市新城区团结小区7号楼
202311231036360980000279内蒙古呼和浩特市赛罕区万达一区底商101

这样拆分完,每个列都无法进行再次拆分了,同时使得数据库结构更加清晰和易于维护,也有利于后期的运营分析。

第二范式(2NF)

第二范式(2NF)要求每个非主键列只依赖于主键而不依赖于其他非主键列,具体的应用场景是联合主键(多个字段共同充当表的主键),这里通过以下例子来进行说明(订单编号和产品编码组成联合主键):

订单编号产品编号购买价格购买数量订单总金额购买时间
202311212056485430000001202311212056485430000003100.0022302023/11/21 20:56:48
20231121205648543000000120231121205648543000000430.0012302023/11/21 20:56:48
2023112310363609800002022023112120564854300000059.99134.992023/11/23 10:36:36
20231123103636098000020220231121205648543000000610.00134.992023/11/23 10:36:36
20231123103636098000020220231121205648543000000715.00134.992023/11/23 10:36:36

直接看感觉没有什么毛病,但是我们来对上表的字段进行分析:

  • 购买价格:购买价格完全依赖订单编号+产品编号,订单编号+产品编号同时确定才能确定购买价格(同一产品在不同的订单会有不同的价格);
  • 购买数量:购买数量完全依赖订单编号+产品编号;订单编号+产品编号同时确定才能确定购买数量;
  • 订单总金额:订单总金额只依赖于订单编号,和实际的产品没有关系,我们通过订单编号就可以明确订单总金额;所以该字段违背了第二范式(2NF);
  • 购买时间:购买时间只依赖于订单编号,一个订单的所有商品肯定是同一时间购买的,该字段很明显和产品编号是无任何依赖关系的;所以该字段也违背了第二范式(2NF)。

现在我们进行优化,进行表拆分,拆分后得到两个表:

订单编号产品编号购买价格购买数量
202311212056485430000001202311212056485430000003100.002
20231121205648543000000120231121205648543000000430.001
2023112310363609800002022023112120564854300000059.991
20231123103636098000020220231121205648543000000610.001
20231123103636098000020220231121205648543000000715.001
订单编号订单总金额购买时间
2023112120564854300000012302023/11/21 20:56:48
20231123103636098000020234.992023/11/23 10:36:36

这样拆分完后,就符合了第二范式(2NF),同时数据结构更加清晰,也减少了数据冗余。

第三范式(3NF)

第三范式(3NF)说直白点就是表中的非主键字段和主键字段直接相关,不允许间接相关。下面通过一个表来进行说明(主键:部门ID)。

部门ID部门名称负责人负责人性别负责人年龄
202311212056485430000001综合支撑部张三35
202311212056485430000002人力资源部李四41

很明显,部门名称和负责人和部门ID是直接关联了,而负责人性别和负责人年龄和部门ID并没有直接关系,而是和负责人直接关联的,所以就存在这种传递依赖关系了。

部门ID->负责人->负责人性别
部门ID->负责人->负责人年龄

这就违反了第三范式(3NF),这个时候就需要把上表拆分成两张表,以外键形式关联。如下所示:

部门ID部门名称负责人ID
202311212056485430000001综合支撑部202311212056485430000003
202311212056485430000002人力资源部202311212056485430000004
负责人ID姓名性别年龄
202311212056485430000003张三35
202311212056485430000004李四41

这样拆分后,结构立马清晰了,每个表存储的数据也都是单一的。

总结

在日常开发中,我们少不了进行功能模块的数据库建模,而数据库三范式是设计数据库表结构的规则约束,通过遵循三范式,可以减少数据冗余、提高数据的一致性和准确性,并且简化数据库的设计和维护。

但是通过上面的分析,我们遵循了三范式,就会多了好几张表,导致在一些业务复杂的场景,就会出现多表关联查询效率低的问题。所以,有的时候进行系统性能优化时,也会打破三范式规则,进行局部变通,做到根据具体业务场景活学活用。

但凡事都有一个但是,但是在实际开发中允许局部变通。

一个三线城市的国企码农,热爱技术,在这里和大家分享在国企搞技术的点点滴滴。欢迎大家关注我的微信公众号:果冻想


果冻想
430 声望30 粉丝