SQL笔记 -- 范式(第一范式、第二范式、第三范式、巴斯范式、反范式)及数据库设计原则

1.范式

1.1 范式简介

在关系型数据库中,关于数据表设计的基本原则、规则就称为范式。可以理解为,一张数据表的设计结构需要满足的某种设计标准的级别 。要想设计一个结构合理的关系型数据库,必须满足一定的范式。

目前关系型数据库有六种常见范式,按照范式级别,从低到高分别是:第一范式(1NF)、第二范式 (2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。

数据库的范式设计越高阶,冗余度就越低,同时高阶的范式一定符合低阶范式的要求,满足最低要求的范式是第一范式(1NF)。在第一范式的基础上进一步满足更多规范的要求称为第二范式(2NF),其余范式以此类推。

一般来说,在关系型数据库设计中,最高也就遵循到BCNF, 普遍还是3NF。但也不绝对,有时候为了提高某些查询性能,我们还需要破坏范式规则,也就是反规范化。

1.2 第一范式

第一范式主要确保数据库中每个字段的值必须具有原子性,也就是说数据表中每个字段的值为不可再次拆分的最小数据单元。我们在设计某个字段的时候,对于字段X来说,不能把字段X拆分成字段X-1和字段X-2。事实上,任何的DBMS都会满足第一范式的要求,不会将字段进行拆分。

1.3 第二范式

第二范式要求,在满足第一范式的基础上,还要满足数据库里的每一条数据记录,都是可唯一标识的。而且所有非主键字段,都必须完全依赖主键,不能只依赖主键的一部分。如果知道主键的所有属性的值,就可以检索到任何元组(行)的任何属性的任何值。(要求中的主键,其实可以扩展替换为候选键)。

例如:

比赛表 player_game ,里面包含球员编号、姓名、年龄、比赛编号、比赛时间和比赛场地等属性,这里候选键和主键都为(球员编号,比赛编号),我们可以通过候选键(或主键)来决定如下的关系:

mysql 复制代码
(球员编号, 比赛编号) → (姓名, 年龄, 比赛时间, 比赛场地,得分)

但是这个数据表不满足第二范式,因为数据表中的字段之间还存在着如下的对应关系:

mysql 复制代码
(球员编号) → (姓名,年龄)

(比赛编号) → (比赛时间, 比赛场地)

对于非主属性来说,并非完全依赖候选键。

1.4 第三范式

第三范式是在第二范式的基础上,确保数据表中的每一个非主键字段都和主键字段直接相关,也就是说,要求数据表中的所有非主键字段不能依赖于其他非主键字段。(即,不能存在非主属性A依赖于非主属性B,非主属性B依赖于主键C的情况,即存在"A->B->C"的决定关系)通俗地讲,该规则的意思是所有非主键属性之间不能由依赖关系,必须相互独立。这里的主键可以扩展为候选键。

例如:

球员player表,里面包含球员编号、姓名、球队名称和球队主教练等属性。这里候选键和主键为球员编号,我们可以通过候选键(或主键)来决定如下的关系:

mysql 复制代码
球员编号 → (球员姓名、球队名称和球队主教练)

能看到球员编号决定了球队名称,同时球队名称决定了球队主教练,非主属性球队主教练就会传递依赖于球员编号,因此不符合 3NF 的要求。

如果要达到 3NF 的要求,需要把数据表拆成下面这样:

mysql 复制代码
球员表 :球员编号、姓名、球队名称
球队表 :球队名称、球队主教练

1.5 巴斯范式(BCNF)

人们在3NF的基础上进行了改进,提出了巴斯范式(BCNF),也叫巴斯 - 科德范式(Boyce - Codd Normal Form)。BCNF被认为没有新的设计规范加入,只是对第三范式中设计规范要求更强,使得数据库冗余度更小。若一个关系达到了第三范式,并且它只有一个候选键,或者它的每个候选键都是单属性,则该关系自然达到BC范式。一般来说,一个数据库设符合3NF或者BCNF就可以了。

例如:

仓库表,里面包含仓库名,管理员,物品名,数量等属性,且管理员和仓库名一一对应。这里候选键是(管理员,物品名)和(仓库名,物品名),然后我们从候选键中选择一个作为主键 ,比 如(仓库名,物品名)。可以看到主属性仓库名对于候选键(管理员,物品名)是部分依赖的关系,不满足BCNF。

如果要达到 BCNF 的要求,需要把数据表拆成下面这样:

mysql 复制代码
仓库表 :(仓库名,管理员)
库存表 :(仓库名,物品名,数量)

1.6 反范式化

1.6.1 概述

规范化 vs 性能

  1. 为满足某种商业目标 , 数据库性能比规范化数据库更重要
  2. 在数据规范化的同时 , 要综合考虑数据库的性能
  3. 通过在给定的表中添加额外的字段,以大量减少需要从中搜索信息所需的时间
  4. 通过在给定的表中插入计算列,以方便查询

虽然规范化可以避免数据上的冗余,但也不是越规范越好。在实际应用场景中,也要考虑性能综合分析。

例如:

员工的信息存储在 employees 表中,部门信息存储在departments 表中。通过 employees 表中的 department_id字段与 departments 表建立关联关系。如果要查询一个员工所在部门的名称:

mysql 复制代码
select employee_id,department_name
from employees e join departments d
on e.department_id = d.department_id;

如果经常需要进行这个操作,连接查询就会浪费很多时间。可以在 employees 表中增加一个冗余字段 department_name,这样就不用每次都进行连接操作了。

1.6.2 反范式的缺点
  • 存储空间变大了
  • 一个表中字段做了修改,另一个表中冗余的字段也需要做同步修改,否则数据不一致
  • 若采用存储过程来支持数据的更新、删除等额外操作,如果更新频繁,会非常消耗系统资源
  • 在 数据量小的情况下,反范式不能体现性能的优势,可能还会让数据库的设计更加复杂
1.6.3 适用场景

当冗余信息有价值或者能大幅度提高查询效率的时候,我们才会采取反范式的优化。

(1)增加冗余字段的建议

增加冗余字段一定要符合如下两个条件。只要满足这两个条件,才可以考虑增加夯余字段。

  • 这个冗余字段不需要经常进行修改。

  • 这个冗余字段查询的时候不可或缺。

(2)历史快照、历史数据的需要

在现实生活中,我们经常需要一些冗余信息,比如订单中的收货人信息,包括姓名、电话和地址等。每 次发生的订单收货信息都属于历史快照,需要进行保存,但用户可以随时修改自己的信息,这时保存这 些冗余信息是非常有必要的。

反范式优化也常用在数据仓库的设计中,因为数据仓库通常存储历史数据 ,对增删改的实时性要求不强,对历史数据的分析需求强。这时适当允许数据的冗余度,更方便进行数据分析。

2. 数据库设计原则

  • 数据表的个数越少越好

  • 数据表中的字段个数越少越好

  • 数据表中联合主键的字段个数越少越好

  • 使用主键和外键越多越好

相关推荐
科技小花4 小时前
数据治理平台架构演进观察:AI原生设计如何重构企业数据管理范式
数据库·重构·架构·数据治理·ai-native·ai原生
一江寒逸4 小时前
零基础从入门到精通MySQL(中篇):进阶篇——吃透多表查询、事务核心与高级特性,搞定复杂业务SQL
数据库·sql·mysql
D4c-lovetrain4 小时前
linux个人心得22 (mysql)
数据库·mysql
阿里小阿希4 小时前
CentOS7 PostgreSQL 9.2 升级到 15 完整教程
数据库·postgresql
荒川之神4 小时前
Oracle 数据仓库雪花模型设计(完整实战方案)
数据库·数据仓库·oracle
做个文艺程序员5 小时前
MySQL安全加固十大硬核操作
数据库·mysql·安全
不吃香菜学java5 小时前
Redis简单应用
数据库·spring boot·tomcat·maven
一个天蝎座 白勺 程序猿5 小时前
Apache IoTDB(15):IoTDB查询写回(INTO子句)深度解析——从语法到实战的ETL全链路指南
数据库·apache·etl·iotdb
不知名的老吴5 小时前
Redis的延迟瓶颈:TCP栈开销无法避免
数据库·redis·缓存
YOU OU5 小时前
三大范式和E-R图
数据库