当前位置: 首页 > news >正文

数据库范式设计

课程地址

范式设计的根本目的在于降低数据不一致造成风险的可能性

教科书级别的范式定义:符合某一种级别的关系模式的集合,表示一个关系内部各属性之间的联系的合理化程度

从 1NF 到 5NF 是递进的关系,也就是满足了 2NF 一定满足了 1NF,满足了 3NF 一定满足了 1NF & 2NF

在实际应用中,以前 3 个范式最为重要

4NF 主要是在描述多对多关系如何建立,显然通过引入“关系表”来描述多对多关系比较合适

1NF

不能借助行的顺序传达任何信息

列的数据类型保持一致

必须要有主键

最重要的:符合1NF的关系中的每个属性都不可再分(原子性),例如如下多级表头的表格:

在这里插入图片描述
可以改进为如下的表格:
在这里插入图片描述

1NF是所有关系型数据库的最基本要求,也就是 MySQL 等 RDMS 天然地满足了 1NF

2NF

假设现在我们有一个游戏业务,需要记录每个玩家的 id,每个玩家持有的物品以及数量,还有每个玩家的等级

则我们设计出下面这张表:

在这里插入图片描述

这样做会造成删除异常、更新异常、新增异常:

假设 gila19 用户丢失了她的全部铜币(或者换成了其他物品),那么应当删除本行,但是这样做 PlayerRating 字段也被删除了,等级信息丢失,这是一种删除异常

在这里插入图片描述

假设我们更新 jdog21 用户的等级,正常情况下应该将 2 个 Intermediate 都更新为 Advanced,但是因为某些原因更新错误,这样就出现了逻辑的不一致,这是一种更新异常

假设我们想新增新用户 tina42,它的初始等级应该是 Beginner,但是因为她初始没有任何资产,所以 2 个 Item 列为空,不能插入数据,这是一种插入异常

第二范式:每个非主键列必须依赖于整个主键列的全部( Each non-key attribute must depend on the entire primary key)

或者反过来讲:表中的主键或联合主键,能够决定除该主键外的所有非主键值。通俗地讲:一张表只能描述一件事

上表中 ItemQuantity 列是符合第二范式的,因为物品数量既要表明它属于哪个用户,也要表明它是什么类型的物品,形式化表示为: { P l a y e r I D , I t e m T y p e } − > { I t e m Q u a n t i e y } \{PlayerID, ItemType\}->\{ItemQuantiey\} {PlayerID,ItemType}>{ItemQuantiey},前者构成了主键的全部

但是 PlayerRating 明显只依赖于 PlayerID 列,而跟 ItemType 无关,形式化表示为: { P l a y e r I D } − > { P l a y e r R a t i n g } \{PlayerID\}->\{PlayerRating\} {PlayerID}>{PlayerRating}

所以上表是一种不符合第二范式的依赖关系

在这里插入图片描述

我们意识到,PlayerRating 是 PlayerID 的一个重要属性(包括将来可能扩展的其他用户信息,包括用户年龄,性别等),这些信息应该单独拉到一个表中

而用户的资产独立到另外一个表中,使得 2 张表都能满足第二范式

3NF

在这里插入图片描述

我们继续扩充 Player 表,增加 PlayerSkillLevel 列,它的值从 1 到 9,与 PlayerRating 3 : 1 对应

假设某天将 gila19 的 PlayerSkillLevel 更新到 4,则需要将她的 PlayerRating 也更新到 Intermediate,但是这个过程一旦出错,就出现了数据不一致的问题

我们分析上面的依赖关系:

{ P l a y e r I D } − > { P l a y e r S k i l l L e v e l } \{PlayerID\}->\{PlayerSkillLevel\} {PlayerID}>{PlayerSkillLevel}

{ P l a y e r I D } − > { P l a y e r S k i l l L e v e l } − > { P l a y e r R a t i n g } \{PlayerID\}->\{PlayerSkillLevel\}->\{PlayerRating\} {PlayerID}>{PlayerSkillLevel}>{PlayerRating}

上面 PlayerRating 依赖于 PlayerSkillLevel,这不符合第三范式:

第三范式:一个非主键类型的属性不能依赖于另一个非主键类型的属性(这种依赖可能会在更新时导致数据不一致)

在这里插入图片描述

为了解决这个问题,只需将 PlayerRating 依赖于 PlayerSkillLevel 提取到另外一张表即可

3NF: Every non-key attribute in a table should depend on the key, the whole key, and nothing but the key

BCNF: Every attribute in a table shold depend on the key, the whole key, and nothing but the key

4NF

设想我们需要存储多对多关系的场景,例如下面的 Model、Color 和 Style 之间构成了多对多的关系

在这里插入图片描述

在这里插入图片描述
当我们需要为 Model = Praire 新增一个颜色 Green 时,需要增加 2 个行,但是这样做一旦少增加了一行(Green Schoolhouse),就会造成数据不一致:只有绿色的 Bungalow 而没有绿色的 Schoolhouse

第四范式:表格中允许的多值依赖关系只能是对主键的多值依赖关系

在这里插入图片描述

5NF

在这里插入图片描述

设想这样一个场景,有 3 个冰激凌品牌:Frosty’s, Alpline, Ice Queen,每个品牌下面有若干口味

Jason 和 Suzy 分别有自己喜欢的品牌和口味,我们将其记录到表中

现在 Suzy 新增了一个喜欢的品牌:Frosty’s,因为她喜欢的口味是 rum raisin, mint chocolate chip and strawberry,后 2 者在 Frosty’s 中都有,所以需要新增 2 行

还是老问题,如果第二行新增失败,就会出现数据不一致的问题

在这里插入图片描述
解决办法还是解构(拆表格),分别记录每个人喜欢的品牌和口味

第五范式:数据库表格不能看作其他表格逻辑连接在一起的结果

总结

在这里插入图片描述


http://www.mrgr.cn/news/66028.html

相关文章:

  • C++ 的 new 操作符与 C 语言的 malloc 函数的区别
  • 《毛选》:变优秀最直接的方法,学会复盘
  • Python爬虫如何处理验证码与登录
  • clickhouse运维篇(三):生产环境一键生成配置并快速部署ck集群
  • 创维E900-S_华为EC6108V9_v9u_海思hi3798mv100华为系统优盘刷机固件包
  • C++线程池
  • Stable Diffusion(2024)Ai绘画AIGC最新安装包资源下载+自学教程
  • w020基于Java的免税商品优选购物商城设计与实现
  • 103 - Lecture 2 Table and Data Part 1
  • 瑞芯微RK3568开发板Linux编译报错404怎么办?触觉智能教你轻松解决
  • 利士策分享,青年暴富难守,因何在?
  • Visitor 访问者模式
  • 【喂饭级AI教程】手把手教你在本机安装Stable Diffusion秋包【附带全套资源】
  • uniapp中echarts的正确集成方式:Vue2与Vue3组合式API双重视角
  • Java 序列化:深入探索 Serializable 接口
  • SpringBoot在线教育系统:安全与维护
  • Rust数据NoSQL 数据库的使用
  • 蒙特卡洛树搜索(MCTS)
  • 虚拟仿真平台在中医针灸实训室实验课程中的应用
  • 【ARM Linux 系统稳定性分析入门及渐进 1.9.1 -- Crash 命令 System State 集合】
  • Wecom酱搭建企业微信发送消息
  • 华为OD机试 - 删除字符串中出现次数最少的字符 (Java 2024 E卷 100分)
  • 手把手教程:使用 Fluentbit 采集夜莺日志写入 ElasticSearch
  • 目前的AI 到底是背出了答案,还是推理出了答案?
  • 计算生物学与生物信息学漫谈-5-mapping算法
  • 集合数据结构之哈希集、有序集合