数据库表设计范式
华子目录
- MYSQL库表设计:范式
- 第一范式(1NF)
- 第二范式(2NF)
- 第三范式(3NF)
- 三范式小结
- 巴斯-科德范式(BCNF)
- 第四范式(4NF)
- 第五范式(5NF)/完美范式
- 第六范式(6NF)/域键范式
- 反范式
- 数据库范式设计总结
MYSQL库表设计:范式

-
MySQL的库表设计,在很多时候我们都是率性而为,往往在前期的设计中考虑并不全面,同时对于库表结构的划分也并不明确,所以很多时候在开发过程中,代码敲着敲着会去重构某张表结构,甚至大面积重构多张表结构,这种随心所欲的设计方式,无疑给开发造成了很大困扰。 -
范式(
Normal Form)是指设计数据库时要遵守的一些原则 -
在设计
DB库表结构时,需要遵守该规范,可以让在项目之初,设计的库表结构更为合理且优雅。数据库范式中,声名远扬的有三大范式,但除此之外也有一些其他设计规范,如:- 数据库三大范式(
1NF、2NF、3NF) - 第四范式(
4NF)和第五范式:完美范式(5NF) - 巴斯-科德范式(
BCNF) - 域键范式
- 反范式设计
- 数据库三大范式(
-
小结:三大范式之间,是递进的关系,后续的范式都基于前一个范式的基础上推行,比如:今天我要先炒菜,然后吃饭,最后洗碗,这三者属于递进关系,后者都建立在前者之上,其顺序不能颠倒,比如先吃饭再炒菜,这必然是行不通的。数据库的三大范式也一样,第二范式必须建立在第一范式的基础之上,如若设计的库表第一范式都不满足,那定然是无法满足第二范式的。
第一范式(1NF)
- 原则:库表设计时为了确保原子性,其存储数据具备不可再分性,,例:

- 在上述的学生表中,其中有一个
student学生列,这一列存储的数据原则明显不符合第一范式:原子性的规定,因为这一列的数据还可以再拆分为姓名、性别、身高三项数据,因此为了符合第一范式,应该将表结构更改为:

- 如果不去拆分列满足第一范式,会造成什么影响?
- 客户端语言和表之间无法很好的生成映射关系。
- 查询到数据后,需要处理数据时,还需要对
student字段进行额外拆分。 - 插入数据时,对于第一个字段的值还需要先拼装后才能进行写入。
第二范式(2NF)
- 原则:表中的所有列,其数据都必须依赖于主键,也就是一张表只存储同一类型的数据,不能有任何一列数据与主键没有关系,例:

- 虽然此时已经满足了数据库的第一范式,但此刻观察
course课程、score分数这两列数据,跟前面的几列数据实际上依赖关系并不大,同时也由于这样的结构,导致前面几列的数据出现了大量冗余,所以此时可以再次拆分一下表结构:

- 经过上述结构优化后,之前的一张表被拆分成学生表、课程表、成绩表三张,每张表中的
id字段作为主键,其他字段都依赖这个主键。无论在那张表中,都可以通过id主键确定其他字段的信息,每张表的业务属性都具备“唯一性”,也就是每张表都只会描述了“一件事情”,不会存在一张表中会出现两个业务属性。
第三范式(3NF)
- 原则:表中每一列数据不能与主键之外的字段有直接关系,例:

- 比如这张学生表,目前即符合第一范式,也符合第二范式,但看最后的两个字段,
department表示当前学生所属的院校,dean则表示这个院系的院长是谁。一般来说,一个学生的院长是谁,首先是取决于学生所在的院系的,因此最后的dean字段明显与department字段存在依赖关系,因此需要进一步调整表结构:

- 经过进一步的结构优化后,又将原本的学生表拆为了院系表、学生表两张,学生表中则是只存储一个院系
ID,由院系表存储院系相关的所有数据。至此,学生表中的每个非主键字段与其他非主键字段之间,都是相互独立的,之间不会再存在任何依赖性,所有的字段都依赖于主键。 - 为什么要这样调整?不调整会发生什么问题:
- 当一个院系的院长换人后,需要同时修改学生表中的多条数据。
- 当一个院长离职后,需要删除该院长的记录,会同时删除多条学生信息。
- …
- 如果设计的表结构,无法满足第三范式,在操作表时就会出现异常,使得整个表较难维护。
三范式小结
- 范式小结
- 1NF:确保原子性,表中每一个列数据都必须是不可再分的字段。
- 2NF:确保唯一性,每张表都只描述一种业务属性,一张表只描述一件事。
- 3NF:确保独立性,表中除主键外,每个字段之间不存在任何依赖,都是独立的。
- 没有按照范式设计表时,会存在几个问题
- 整张表数据比较冗余,同一个学生信息会出现多条。
- 表结构特别臃肿,不易于操作,要新增一个学生信息时,需添加大量数据。
- 需要更新其他业务属性的数据时,比如院系院长换人了,需要修改所有学生的记录。
- 经过三范式的设计优化后,整个库中的所有表结构,会显得更为优雅,灵活性也会更强。
巴斯-科德范式(BCNF)
- 概念:
- 前题:一般在一张表中,可以用于区分每行数据的一个列,通常会被咱们设为主键,例如常用的
ID字段就是如此,这类主键通常被称为单一主键,即一个列组成的主键。但除此之外,还有一个联合主键的概念,也就是由多个列组成的主键 - 巴斯-科德范式也被称为
3.5NF,是第三范式的补充版 - 第三范式的要求是:任何非主键字段不能与其他非主键字段间存在依赖关系,也就是要求每个非主键字段之间要具备独立性。而巴斯-科德范式在第三范式的基础上,进一步要求:任何主属性不能对其他主键子集存在依赖。
- 大白话:规定了联合主键中的某列值,不能与联合主键中的其他列存在依赖关系
- 前题:一般在一张表中,可以用于区分每行数据的一个列,通常会被咱们设为主键,例如常用的
- 例:

- 分析
- 这张学生表,此时假设以
classes班级字段、class_adviser班主任字段、name学生姓名字段,组合成一个联合主键,在这里我们可以通过联合主键,确定学生表中任何一个学生的信息,比如:熊竹老师管的计算机-2201班,哪个竹子同学有多高啊?可以通过上述的联合主键精准定位到表中第一条数据,并且最终能够给出答案为185cm。 - 出现问题:在这张表中,一条学生信息中的班主任,取决于学生所在的班级,比如「竹子同学、子竹同学」在「计算机-2201班」,所以它们的班主任都是「熊竹老师」,因此班主任字段其实也依赖于班级字段。那会造成什么问题呢?
- 当一个班级的班主任老师换人后,需要同时修改学生表中的多条数据。
- 当一个班主任老师离职后,需要删除该老师的记录,会同时删除多条学生信息。
- 想要增加一个班级时,同时必须添加学生姓名数据,因为主键不允许为空。
- 这张学生表,此时假设以
- 通过上述分析可以明显得知,如果联合主键中的一个字段依赖于另一个字段,同样也会造成不小的问题,使得整张表的维护性变差,因此这里需要进一步调整结构:

-
经过结构调整后:
- 原本的学生表则又被拆为了班级表、学生表两张,在学生表中只存储班级
ID,然后使用classes_id班级ID和name学生姓名两个字段作为联合主键。 - 之前的三个问题也不存在,如换班主任后只需要更改班级表,无需修改学生表中的学生信息;增加班级时,只需要在班级表中新增数据,也不会影响学生表。
- 原本的学生表则又被拆为了班级表、学生表两张,在学生表中只存储班级
-
小结:第三范式只要求非主键字段之间,不能存在依赖关系,但没要求联合主键中的字段不能存在依赖,因此第三范式并未考虑完善,巴斯-科德范式修正的就是这点,是对第三范式的补充及完善,修正了第三范式。
第四范式(4NF)
- 多值依赖:表中的字段之间存在一对多的关系,也就是一个字段的具体值会由多个字段来决定(一个表中至少需要有三个独立的字段才会出现多值依赖问题)
- 示例:

经典的业务,用户角色权限表,各字段含义:
user_name字段 – 用户名
role字段 – 角色信息:
USER:普通用户角色。ADMIN:管理员角色。ROOT:超级管理员角色。
permission字段 – 权限信息:
*:超级管理员拥有的权限级别,*表示所有。BACKSTAGE:管理员拥有的权限级别,表示可以操作后台。LOGIN:普通用户拥有的权限级别,表示可以登录访问平台。
-
此时假设我们需要新增一条数据,那表中的权限字段究竟填什么?这个值是需要依赖多个字段决定的,权限来自于角色,而角色则来自于用户。也就是说,一个用户可以拥有多个角色,同时一个角色可以拥有多个权限,所以此时咱们无法单独根据用户名去确定权限值,权限值必须依赖用户、角色两个字段来决定,这种一个字段的值取决于多个字段才能确定的情况,就被称为多值依赖。
-
因此第四范式的定义就是要消除表中的多值依赖关系,上述表格拆分为:


- 观察上述的五张表正是大名鼎鼎的权限五表,将原本的用户角色权限表,拆分成了用户表、角色表、权限表、用户角色关系表、角色权限关系表。
- 经过这次拆分之后,一方面用户表、角色表、权限表中都不会有数据冗余,第二方面无论是要删除亦或新增一个角色、权限时,都不会影响其他表。后面的两张关系表,主要是为了维护用户、角色、权限三者之间的关系。
第五范式(5NF)/完美范式
-
定义:建立在
4NF的基础上,进一步消除表中的连接依赖,直到表中的连接依赖都是主键所蕴含的 -
第五范式解决的是无损连接问题,基本没有实际意义,了解即可,因为无损连接很少出现,而且难以察觉
第六范式(6NF)/域键范式
- 域键范式,也被称之为终极范式,但目前也仅有学术机构在研究,在生产环境中实际的用途也不大
反范式
-
概念:不遵循数据库范式设计的结构,就被称为反范式结构。
-
遵循数据库范式设计优点如下:
- 避免了大量的数据冗余
- 节省了大量存储空间
- 表整体结构更为优雅,能让
SQL操作更加便捷且减少出错。
-
但随着范式的级别越高,设计出的结构会更加精细化,原本一张表的数据会被分摊到多张表中存储,表的数量随之越来越多。会存在一个致命问题,也就是当同时需要这些数据时,只能采用联表查询的形式检索数据,有时候甚至为了一个字段的数据,也需要做一次连表查询才能获得。这其中的开销无疑是花费巨大的,尤其是当连接的表不仅两三张而是很多张时,有可能还会造成索引失效,这种情况带来的资源、时间开销简直是一个噩梦,这会严重地影响整个业务系统的性能。
-
因此,也正是由于上述一些问题,在设计库表结构时,我们不一定要
100%遵守范式准则。这种违反数据库范式的设计方法,就被称之为 反范式设计。 -
设计原则:无论那种范式只要能够对业务有利,那就可以称之为好的设计方案。在设计时千万不要拘泥于规则之内,一定要结合实际业务考虑,遵循业务优先的原则去设计结构。
-
注意:不是所有不遵循数据库范式的结构设计都被称为反范式,反范式设计是指自己知道会破坏范式,但对业务带来好处大于坏处时,刻意设计出破坏范式的结构。
数据库范式设计总结
- 经过一系列的阐述后,其实不难发现,越到后面的范式,越难令人理解,同时为了让表满足更高级别的范式,越往后付出代价也越大,而且拆分出的表数量也会越多
- 一般项目中仅需满足到第三范式或
BC范式即可,因为这个度刚刚好,再往后就会因为过于精细化设计,导致整体性能反而下降。 - 控制到第三范式的级别,一方面数据不会有太多冗余,第二方面也不会对性能影响过大。同时,如若打破范式的设定能对业务更有利,那也可以违背范式原则去设计。
- 生产项目中库表结构设计的是否合理,区别如下:
- 不合理的结构设计会造成的问题:
- 数据冗余,会浪费一定程度上的存储空间
- 不便于常规
SQL操作(例如插入、删除),甚至会出现异常
- 合理的结构设计带来的好处:
- 节省空间,
SQL执行时能节省内存空间,数据存储时能节省磁盘空间 - 数据划分较为合理,
DB性能整体较高,并且数据也非常完整 - 结构便于维护和进行常规
SQL操作
- 节省空间,
- 不合理的结构设计会造成的问题:
- 各范式之间的递进关系图:

范式概念:
- 第一范式:原子性,每个字段的值不能再分。
- 第二范式:唯一性,表内每行数据必须描述同一业务属性的数据。
- 第三范式:独立性,表中每个非主键字段之间不能存在依赖性。
- 巴斯范式:主键字段独立性,联合主键字段之间不能存在依赖性。
- 第四范式:表中字段不能存在多值依赖关系。
- 第五范式:表中字段的数据之间不能存在连接依赖关系。
- 域键范式:试图研究出一个库表设计时的终极完美范式。
相关文章:
数据库表设计范式
华子目录 MYSQL库表设计:范式第一范式(1NF)第二范式(2NF)第三范式(3NF)三范式小结巴斯-科德范式(BCNF)第四范式(4NF)第五范式(5NF&…...
经济增长初步
1.人均产出 人均产出,通常指的是一个国家、地区或组织在一定时期内,每个劳动人口平均创造的生产总值。它是衡量一个地区或国家经济效率和劳动生产率的重要指标。具体来说,人均产出可以通过以下公式计算: 人均产出总产出/劳动人口…...
【架构】主流企业架构Zachman、ToGAF、FEA、DoDAF介绍
文章目录 前言一、Zachman架构二、ToGAF架构三、FEA架构四、DoDAF 前言 企业架构(Enterprise Architecture,EA)是指企业在信息技术和业务流程方面的整体设计和规划。 最近接触到“企业架构”这个概念,转念一想必定和我们软件架构…...
时间请求参数、响应
(7)时间请求参数 1.默认格式转换 控制器 RequestMapping("/commonDate") ResponseBody public String commonDate(Date date){System.out.println("默认格式时间参数 date > "date);return "{module : commonDate}"; }…...
PyTorch图像预处理:计算均值和方差以实现标准化
在深度学习中,图像数据的预处理是一个关键步骤,它直接影响模型的训练效果和收敛速度。PyTorch提供的transforms.Normalize()函数允许我们对图像数据进行标准化处理,即减去均值并除以方差。这一步骤对于提高模型性能至关重要。 为什么需要标准…...
slice介绍slice查看器
Android Jetpack架构组件(十)之Slices - 阅读清单 - 腾讯云开发者社区-腾讯云 slice 查看器apk 用adb intall 安装 Releases android/user-interface-samples GitHubMultiple samples showing the best practices in the user interface on Android. - Releases android/u…...
Android音频采集
在 Android 开发领域,音频采集是一项非常重要且有趣的功能。它为各种应用程序,如语音聊天、音频录制、多媒体内容创作等提供了基础支持。今天我们就来深入探讨一下 Android 音频采集的两大类型:Mic 音频采集和系统音频采集。 1. Mic音频采集…...
通过轻易云平台实现聚水潭数据高效集成到MySQL的技术方案
聚水潭数据集成到MySQL的技术案例分享 在本次技术案例中,我们将详细探讨如何通过轻易云数据集成平台,将聚水潭的数据高效、可靠地集成到MySQL数据库中。具体方案为“聚水谭-店铺查询单-->BI斯莱蒙-店铺表”。这一过程不仅需要处理大量数据的快速写入…...
类和对象( 中 【补充】)
目录 一 . 赋值运算符重载 1.1 运算符重载 1.2 赋值运算符重载 1.3 日期类实现 1.3.1 比较日期的大小 : 1.3.2 日期天数 : 1.3.3 日期 - 天数 : 1.3.4 前置/后置 1.3.5 日期 - 日期 1.3.6 流插入 << 和 流提取 >> 二 . 取地址运算符重载 2.1 const…...
如何使用gpio模拟mdio通信?
一、前言 实际项目开发中,由于设计原因,会将phy的mdio引脚连接到SoC的2个空闲gpio上, 这样就无法通过Gmac自有的架构实现修改phy, 因此只能通过GPIO模拟的方式实现MDIO, 好在Linux支持MDIO via GPIO功能。 该功能…...
C# 中的事件和委托:构建响应式应用程序
C#中的事件和委托。事件和委托是C#中用于实现观察者模式和异步回调的重要机制,它们在构建响应式和交互式应用程序中发挥着重要作用。以下是一篇关于C#中事件和委托的文章。 引言 事件和委托是C#语言中非常重要的特性,它们允许你实现观察者模式和异步回…...
科技赋能健康:多商户Java版商城系统引领亚健康服务数字化变革
在当今社会,随着生活节奏的加快和工作压力的增大,越来越多的人处于亚健康状态。据《The Lancet》期刊2023年的统计数据显示,全球亚健康状态的人群比例已高达82.8%,这一数字背后,隐藏着巨大的健康风险和社会成本。亚健康…...
区块链网络示意图;Aura共识和Grandpa共识(BFT共识)
目录 区块链网络示意图 Aura共识和Grandpa共识(BFT共识) Aura共识 Grandpa共识(BFT共识) Aura与Grandpa的结合 区块链网络示意图 CP Blockchain:这是中央处理区块链(或可能指某种特定的处理单元区块链)的缩写。它可能代表了该区块链网络的主要处理或存储单元。在这…...
Javaweb梳理18——JavaScript
今日目标 掌握 JavaScript 的基础语法掌握 JavaScript 的常用对象(Array、String)能根据需求灵活运用定时器及通过 js 代码进行页面跳转能通过DOM 对象对标签进行常规操作掌握常用的事件能独立完成表单校验案例 18.1 JavaScript简介 JavaScript 是一门跨…...
面向对象-接口的使用
1. 接口的概述 为什么有接口? 借口是一种规则,对于继承而言,部分子类之间有共同的方法,为了约束方法的使用,使用接口。 接口的应用: 接口不是一类事物,它是对行为的抽象。 2. 接口的定义和使…...
失落的Apache JDBM(Java Database Management)
简介 Apache JDBM(Java Database Management)是一个轻量级的、基于 Java 的嵌入式数据库管理系统。它主要用于在 Java 应用程序中存储和管理数据。这个项目已经过时了,只是发表一下以示纪念,现在已经大多数被SQLite和Derby代替。…...
Vue3+SpringBoot3+Sa-Token+Redis+mysql8通用权限系统
sa-token支持分布式token 前后端代码,地球号: bright12389...
MySQL 三大日志详解
在 MySQL 数据库中,binlog(二进制日志)、redo log(重做日志)和 undo log(回滚日志)起着至关重要的作用。它们共同保障了数据库的高可用性、数据一致性和事务的可靠性。下面将对这三大日志进行详…...
Java 岗面试八股文及答案整理(2024最新版)
春招,秋招,社招,我们 Java 程序员的面试之路,是挺难的,过了 HR,还得被技术面,小刀在去各个厂面试的时候,经常是通宵睡不着觉,头发都脱了一大把,还好最终侥幸能…...
Web3.0安全开发实践:Clarity最佳实践总结
在过去的一段时间里,CertiK团队对比特币生态系统及其发展进行了深入研究。同时,团队还审计了多个比特币项目以及基于不同编程语言的智能合约,包括OKX的BRC-20钱包和MVC DAO的sCrypt智能合约实现。 现在,我们的研究重点转向了Clar…...
浅谈 React Hooks
React Hooks 是 React 16.8 引入的一组 API,用于在函数组件中使用 state 和其他 React 特性(例如生命周期方法、context 等)。Hooks 通过简洁的函数接口,解决了状态与 UI 的高度解耦,通过函数式编程范式实现更灵活 Rea…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
如何为服务器生成TLS证书
TLS(Transport Layer Security)证书是确保网络通信安全的重要手段,它通过加密技术保护传输的数据不被窃听和篡改。在服务器上配置TLS证书,可以使用户通过HTTPS协议安全地访问您的网站。本文将详细介绍如何在服务器上生成一个TLS证…...
vue3+vite项目中使用.env文件环境变量方法
vue3vite项目中使用.env文件环境变量方法 .env文件作用命名规则常用的配置项示例使用方法注意事项在vite.config.js文件中读取环境变量方法 .env文件作用 .env 文件用于定义环境变量,这些变量可以在项目中通过 import.meta.env 进行访问。Vite 会自动加载这些环境变…...
RNN避坑指南:从数学推导到LSTM/GRU工业级部署实战流程
本文较长,建议点赞收藏,以免遗失。更多AI大模型应用开发学习视频及资料,尽在聚客AI学院。 本文全面剖析RNN核心原理,深入讲解梯度消失/爆炸问题,并通过LSTM/GRU结构实现解决方案,提供时间序列预测和文本生成…...
(一)单例模式
一、前言 单例模式属于六大创建型模式,即在软件设计过程中,主要关注创建对象的结果,并不关心创建对象的过程及细节。创建型设计模式将类对象的实例化过程进行抽象化接口设计,从而隐藏了类对象的实例是如何被创建的,封装了软件系统使用的具体对象类型。 六大创建型模式包括…...
tomcat指定使用的jdk版本
说明 有时候需要对tomcat配置指定的jdk版本号,此时,我们可以通过以下方式进行配置 设置方式 找到tomcat的bin目录中的setclasspath.bat。如果是linux系统则是setclasspath.sh set JAVA_HOMEC:\Program Files\Java\jdk8 set JRE_HOMEC:\Program Files…...
tauri项目,如何在rust端读取电脑环境变量
如果想在前端通过调用来获取环境变量的值,可以通过标准的依赖: std::env::var(name).ok() 想在前端通过调用来获取,可以写一个command函数: #[tauri::command] pub fn get_env_var(name: String) -> Result<String, Stri…...
十九、【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建
【用户管理与权限 - 篇一】后端基础:用户列表与角色模型的初步构建 前言准备工作第一部分:回顾 Django 内置的 `User` 模型第二部分:设计并创建 `Role` 和 `UserProfile` 模型第三部分:创建 Serializers第四部分:创建 ViewSets第五部分:注册 API 路由第六部分:后端初步测…...
嵌入式学习之系统编程(九)OSI模型、TCP/IP模型、UDP协议网络相关编程(6.3)
目录 一、网络编程--OSI模型 二、网络编程--TCP/IP模型 三、网络接口 四、UDP网络相关编程及主要函数 编辑编辑 UDP的特征 socke函数 bind函数 recvfrom函数(接收函数) sendto函数(发送函数) 五、网络编程之 UDP 用…...
