数据库设计三范式

简介: 本文详解数据库三范式:第一范式要求字段原子性,不可再分;第二范式在满足第一范式基础上,消除部分依赖,确保主键唯一确定非主键;第三范式进一步消除传递依赖。通过实例解析范式应用及拆表优化,指出范式是设计参考,实际需结合项目需求灵活调整,以降低冗余、提升维护效率。

第一范式 - 1NF遵循原子性。即,表中字段的数据,不可以再拆分。先看一个不符合第一范式的表结构,如下:
员工编码 姓名 年龄
001 销售部小张 28
002 运营部小黄 25
003 技术部小高 22
在这一个表中的,姓名 字段下的数据是可以再进行拆分的,因此它不符合第一范式,那怎么样才符合第一范式呢?如下:
员工编码 部门 姓名 年龄
001 销售部 小张 28
002 运营部 小黄 25
003 技术部 小高 22
那是否遵循第一范式就一定是好的呢?如下:
员工编码 姓名 地址
001 小张 江西省南昌市东湖区
002 小黄 广东省佛山市禅城区
003 小高 湖北省武汉市新洲区
通过观察上述表结构,我们发现,地址是可以再进一步拆分的,比如:
员工编码 姓名 省 市 区
001 小张 江西省 南昌市 东湖区
002 小黄 广东省 佛山市 禅城区
003 小高 湖北省 武汉市 新洲区
虽然拆分后,看上去更符合第一范式了,但是如果项目就只需要我们输出一个完整地址呢?那明显是表在没拆分的时候会更好用。所以范式只是给了我们一个参考,我们更多的是要根据项目实际情况设计表结构。第二范式 - 2NF在满足第一范式的情况下,遵循唯一性,消除部分依赖。即,表中任意一个主键或任意一组联合主键,可以确定除该主键外的所有的非主键值。再通俗点讲就是,一个表只能描述一件事情。我们用一个经典案例进行解析。
学号 姓名 年龄 课程名称 成绩 学分
001 小张 28 语文 90 3
001 小张 28 数学 90 2
002 小黄 25 语文 90 3
002 小黄 25 语文 90 3
003 小高 22 数学 90 2
我们先分析一下表结构。1. 假设学号是表中的唯一主键,那由学号就可以确定姓名和年龄了,但是却不能确定课程名称和成绩。2. 假设课程名称是表中的唯一主键,那由课程名称就可以确定学分了,但是却不能确定姓名、年龄和成绩。3. 虽然通过学号和课程名称的联合主键,可以确定除联合主键外的所有的非主键值,但是基于上述两个假设,也不符合第二范式的要求。 那我们应该如何调整表结构,让它能复合第二范式的要求呢?我们可以基于上述的三种主键的可能,拆分成 3 张表,保证一张表只描述一件事情。1. 学生表 - 学号做主键
学号 姓名 年龄
001 小张 28
002 小黄 25
003 小高 22

  1. 课程表 - 课程名称做主键
    课程名称 学分
    语文 3
    数学 2
  2. 成绩表 - 学号和课程名称做联合主键
    学号 课程名称 成绩
    001 语文 90
    001 数学 90
    002 语文 90
    002 语文 90
    003 数学 90
    这时候我们可能会想,为什么我们就要遵循第二范式呢?不遵循第二范式会造成什么样的后果呢?1. 造成整表的数据冗余。如学生表,可能我就只有2个学生,每个学生都有许多的信息,比如,年龄、性别、身高、住址......如果与课程信息放到同一张表中,可能每个学生有3门课程,那数据总条数就会变成6条了。但是通过拆分,学生表我们只需要存储 2 条学生信息,课程表只需要存储 3 条课程信息,成绩表就只需保留学号、课程名称和成绩字段。2. 更新数据不方便。假设,课程的学分发生了变更,那我们就需要把整表关于该课程的学分都要更新一次,但如果我们拆分出课程表,那我们就只需要把课程表中的课程信息更新就行。3. 插入数据不方便或产生异常。① 假设主键是学号或课程名称,我们新增了某个课程,需要把数据插入到表中,这时,可能只有部分人有选修这门课程,那我们插入数据的时候还要规定给哪些人插入对应的课程信息,同时可能由于成绩还没有,我们需要对成绩置空,后续有成绩后还得重新更新一遍。② 假设主键是学号和课程名称的联合主键。同样也是新增了某课程,但是暂时没有人选修这门课,缺少了学号主键字段数据,会导致课程信息无法插入。第三范式 - 3NF在满足第二范式的情况下,消除传递依赖。即,在任一主键都可以确定所有非主键字段值的情况下,不能存在某非主键字段 A 可以获取 某非主键字段 B。仍然用一个经典例子来解析
    学号 姓名 班级 班主任
    001 小黄 一年级(1)班 高老师
    这个表中,学号是主键,它可以唯一确定姓名、班级、班主任,符合了第二范式,但是在非主键字段中,我们也可以通过班级推导出该班级的班主任,所以它是不符合第三范式的。那怎么设计表结构,才是符合第三范式的呢?1. 学生表
    学号 姓名 班级
    001 小黄 一年级(1)班
  3. 班级表
    班级 班主任
    一年级(1)班 高老师
    通过把班级与班主任的映射关系另外做成一张映射表,我们就成功地消除了表中的传递依赖了。总结不知道读者们有没有发现,以上所介绍的范式的最终目的都是为了减少我们的工作量呢?所以说,尽管范式是一种很好的指导规范,但在实际应用中,我们也不需要太局限在范式中,更多的是应该从项目中出发,设计出合理的表结构。以下是本篇三范式的简单总结:第一范式(1 NF):字段不可再拆分。第二范式(2 NF):表中任意一个主键或任意一组联合主键,可以确定除该主键外的所有的非主键值。第三范式(3 NF):在任一主键都可以确定所有非主键字段值的情况下,不能存在某非主键字段 A 可以获取 某非主键字段 B。
相关文章
|
23小时前
|
人工智能 缓存 自然语言处理
大模型推理与应用术语解释
本文系统介绍了大语言模型核心概念:推理、生成式AI、检索增强生成(RAG)、提示工程、上下文学习、代理、多模态学习与语义搜索。涵盖其原理、应用与优化技术,展现大模型在内容生成、知识融合、任务执行与跨模态理解等方面的前沿进展,揭示高效、智能AI系统的构建路径。
|
21小时前
|
存储 缓存 NoSQL
每日必会6
Redis常见数据结构包括字符串、哈希、列表、集合、有序集合及地理空间索引。持久化机制有AOF和RDB,配合使用可防数据丢失,刷盘策略影响数据安全性。三大问题:缓存雪崩、穿透、击穿,需通过过期时间随机化、布隆过滤器、互斥锁等手段应对。
|
1天前
|
消息中间件 存储 SQL
每日必会5
为确保消息不丢失,RabbitMQ通过生产者确认、消息持久化和消费者确认机制保障。生产者发送消息后根据返回结果判断投递状态;消息及队列均持久化存储;消费者处理完成后需返回ACK。我们采用auto模式+重试机制提升可靠性。
|
21小时前
|
设计模式 缓存 Java
每日必会4
在订单支付完成后通知配送中心等异步、解耦场景中常用MQ,如使用TopicExchange话题模式实现灵活路由。结合Spring的IOC、AOP、三级缓存及事务管理,保障系统稳定与高效。
|
1天前
|
Linux 网络安全 开发工具
每日必会3
熟悉Docker部署,掌握docker run、Dockerfile及docker-compose集群部署;熟练使用镜像与容器相关命令如pull、push、run、exec等;常用Linux命令包括ls、cd、grep、ps、top、chmod、find、ssh、scp、wget等,排查日志常用cat、grep、vim及管道组合查询。
|
21小时前
|
Dubbo Java 应用服务中间件
每日必会2
Gateway基于Spring WebFlux与Netty实现非阻塞高性能通信,启动时创建Netty Server接收请求,通过路由匹配和过滤器处理后转发至目标服务,响应反向经滤器返回。项目远程调用采用OpenFeign,底层为HTTP,也曾使用Dubbo。JVM部分涵盖模型、GC、类加载及调优。
|
1天前
|
负载均衡 中间件 Java
每日必会1
微服务并非绝对优于单体,需结合业务。简单场景下单体更轻便;复杂业务链路适合微服务,降低耦合利于扩展。常用中间件:Nacos(注册/配置中心)、OpenFeign(远程调用)、Gateway(网关)。Nacos支持心跳机制,临时实例异常剔除,非临时实例不剔除,较Eureka更新更及时、模式更灵活。负载均衡常用轮询、加权等,项目中多用轮询。
|
21小时前
|
前端开发 NoSQL Java
低代码IDEA启动项目
本文介绍如何在IDEA中启动Jeecg-Boot前后端项目。先启动Java后端:初始化MySQL与Redis,安装Maven依赖,修改数据库及Redis配置,运行主类启动服务;再启动Vue3前端:安装pnpm依赖,配置代理与接口地址,执行dev命令启动。前端访问http://localhost:3100,账号admin/123456。支持IDEA或VSCode开发。
|
1天前
|
前端开发 Java 数据库
低代码技术架构
后端采用Spring Boot + Spring Cloud Alibaba微服务架构,基于Java 8+/17、Maven、MybatisPlus、Shiro+Jwt、Redis、Druid、Nacos等技术;前端使用Vue3.0 + TypeScript + Vite5 + Ant-Design-Vue4,支持权限控制与动态菜单。需IDEA、WebStorm/Vscode、Node 20+等开发环境。
|
21小时前
|
人工智能 JSON 安全
大模型应用开发中MCP与Function Call的关系与区别
MCP与Function Call是大模型应用的两大关键技术。前者为跨模型工具调用的标准化协议,实现系统解耦与生态扩展;后者是模型调用外部功能的内置机制。二者互补协同,推动AI应用向高效、开放、安全演进。