一文彻底搞懂数据库三范式

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

前言

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

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

数据库三范式

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

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

三范式的定义:

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

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

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

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

第一范式(1NF)

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

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

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

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

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

第二范式(2NF)

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

订单编号 产品编号 购买价格 购买数量 订单总金额 购买时间
202311212056485430000001 202311212056485430000003 100.00 2 230 2023/11/21 20:56:48
202311212056485430000001 202311212056485430000004 30.00 1 230 2023/11/21 20:56:48
202311231036360980000202 202311212056485430000005 9.99 1 34.99 2023/11/23 10:36:36
202311231036360980000202 202311212056485430000006 10.00 1 34.99 2023/11/23 10:36:36
202311231036360980000202 202311212056485430000007 15.00 1 34.99 2023/11/23 10:36:36

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

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

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

订单编号 产品编号 购买价格 购买数量
202311212056485430000001 202311212056485430000003 100.00 2
202311212056485430000001 202311212056485430000004 30.00 1
202311231036360980000202 202311212056485430000005 9.99 1
202311231036360980000202 202311212056485430000006 10.00 1
202311231036360980000202 202311212056485430000007 15.00 1
订单编号 订单总金额 购买时间
202311212056485430000001 230 2023/11/21 20:56:48
202311231036360980000202 34.99 2023/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

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

总结

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

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

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

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

相关推荐
秃头摸鱼侠几秒前
MySQL安装与配置
数据库·mysql·adb
UGOTNOSHOT5 分钟前
每日八股文6.3
数据库·sql
行云流水行云流水29 分钟前
数据库、数据仓库、数据中台、数据湖相关概念
数据库·数据仓库
John Song31 分钟前
Redis 集群批量删除key报错 CROSSSLOT Keys in request don‘t hash to the same slot
数据库·redis·哈希算法
IvanCodes1 小时前
七、Sqoop Job:简化与自动化数据迁移任务及免密执行
大数据·数据库·hadoop·sqoop
tonexuan1 小时前
MySQL 8.0 绿色版安装和配置过程
数据库·mysql
JohnYan1 小时前
工作笔记- 记一次MySQL数据移植表空间错误排除
数据库·后端·mysql
我最厉害。,。2 小时前
Windows权限提升篇&数据库篇&MYSQL&MSSQL&ORACLE&自动化项目
数据库·mysql·sqlserver
远方16092 小时前
20-Oracle 23 ai free Database Sharding-特性验证
数据库·人工智能·oracle
GoodStudyAndDayDayUp2 小时前
初入 python Django 框架总结
数据库·python·django