SQL反模式一书在附录章节给出了设计关系数据库的规范化规则,一个简明的规范化规则清单。

关系是什么

在规范化之前,我们先要理解下关系。

数学中关系定义:两个不同数据域上的值的集合,通过一个条件得到的一个所有可能组合的子集。

怎么理解呢?书中以棒球队和城市举例,比如有一个包含所有棒球队的集合,还有一个包含所有城市的集合,

如果把每个城市和每个球队随意组合进行列表,列表会很长,但其实我们只需要关注“球队和其所属城市的集合”。

所以“关系”:

  1. 作为一种规则,比如城市是指某一支队伍所属城市“
  2. 过滤子集的规则

然后将这个子集存储在数据库一张表中,关系即表示的是表中列与列之间的关系。

数据库表需要满足以下条件:

  1. 行之间没有上下顺序
  2. 列之间没有左右顺序
  3. 重复记录不允许
  4. 每一列只有一个类型,每一行只有一个值
  5. 列中都是数据值,而不是物理存储标识,如Oracle的ROWNUM伪列等

规范化的神话

以下一些对规范化的理解是错误的

  1. 规范化让数据库更慢,不规范让数据库更快
  2. 规范化就是把数据移到子表之中
  3. 规范化就是将属性尽可能的拆分开
  4. 没人需要超过第三范式的规范化标准

很久以前我也是这么认为的,现在经过项目实践以及阅读SQL反模式这本书后,这些观念都是不正确的,比如不规范只能让某一种查询变快,其他业务的查询可能呢个就很困难和很慢,再比如不符合范式使得程序含有了隐藏的Bug。

规范化是保证我们正确的存储数据,保证数据的完整性,如果没有这个基础,就不用谈其他的了。

什么是规范化

书中简明给出了规范化的目标如下:

  1. 以一种我们能理解的方式表示事物
  2. 减少数据的冗余存储,防止异常或者不一致的数据
  3. 支持完整性约束

提供数据的性能并不在以上列表中,但规范化本身保证数据的正确存储,很多时候项目因为错误、不一致、重复的数据出现很多问题,但如果一开始就进行规范化设计,就会避免这些问题,所以在某种程度是提升了效率。

范式

以前只了解一到四范式以及BCNF范式,从本书了解到第六范式和DKNF范式,一般的讲述都是以主键、候选键,主属性、非主属性以及依赖关系来解释范式的,这里了解到不同的解释。

第一范式

  1. 该表必须是一个关系,满足前面关系中数据库表的条件
  2. 表中没有重复组合,并不是记录重复,是指一行中可能有多个来自于同一个集合的值,

比如书中以产品缺陷管理举例,如缺陷标签,下面两个图都不满足第一范式。

第一个表,tag1、tag2、tag3都是来自同一个集合tag

第二个表,tags字段的值为多个值也是来自同一个集合tag

始终记住:关系中的每一行,都是从多个集合的每个集合中选一个值形成的组合

满足第一范式的如下图:

第二范式

  1. 表中存在字段其取值与部分主键字段无关
  2. 表中数据有冗余,更新不当会造成数据异常。

还是刚刚的缺陷标签表,现在要往BugsTags表中增加打标签者以及标签创建者,下图就不符合第二范式

tagger字段是打标签者,coiner是标签创建者,BugsTags表是bug_id和tag复合主键,coiner只与tag有关,与Bug是无关的,即只依赖部分主键,并且coiner取值是重复的,所以不符合第二范式。

如果需要修改某个标签的创建者,如果没有修改掉该表中所有tag为该标签的coiner,就会出现数据不一致,这种情况尤其可能出现在多个人同时修改该值的时候。

但是我这里有一个疑问,这张表符合第一范式吗?tagger和coiner字段都应该来账户集合(如Account表),有两列来自相同的集合应该不符合第一范式呢。除非理解标签创建者和打标签者属于不同集合。

而满足第二范式的设计,是增加一个标签表tags,如下图:

第三范式

第二范式是存在字段只依赖于组合主键中的部分,而第三范式是存在字段不依赖于任何主键,而是依赖其他字段。

如果需要记录处理Bug的工程师的email,下图的设计不符合第三范式:

assigned_email与主键bug_id无关,只由assigned_to这个非主键字段决定,所以不符合第三范式,assigned_email取值也是冗余的,也会有更新问题。

符合第三范式的设计是应该把email放到Accounts表中,email直接与主键关联没有冗余。如下图

BCNF(博伊斯-科德范式)

BCNF范式与第三范式的差异很细微,在第三范式中,所有非主键字段都必须直接依赖于这张表中的所有主键列,而BCNF范式要求主键字段也必须遵循这个规则,一般在一张表有复合主键时有效。

比如,我们有三种Tag类型,描述Bug所造成影响的tag,描述Bug影响子系统的tag,以及Bug修复状态的tag,且要求每一个Bug对于每一种tag类型只能有一个tag,所以这里可能的复合主键有bug_id加上tag,或者复合主键为bug_id加上tag_type,这两种组合都可以定位到一行。

存在两种复合主键,所以下图的设计就不符合BCNF,

这里一个隐含的假设是不同tag_type下的tag是不同的,且一个tag只属于一种tag_type,如果没有这个假设,bug_id加上tag是定位不到一行的。

按照这个假设,以前面符合第二范式和第三范式的设计很项,微妙的差别在于该字段在表中的作用是一般字段呢还是复合主键,符合第三范式的设计如下图:

第四范式

随着业务应用复杂度的提升,比如需要支持多个用户报告同一个Bug,并可以分配给多个开发工程师,然后由多个质量工程师验证。这属于多对多的关系,   所以我们需要额外的一张表,如下图不符合第四范式:

这里不能单独使用bug_id作为主键。每个Bug需要多行数据来实现各个字段都支持多个账号的目的,主键需为bug_id、reported_by、assigned_to、verified_by的复合主键,然而bug报告时,是不需要立即进行分配和验证的,所以assigned_to和verified_by需要可以为null,而标准情况下主键是不能为null的。

另外的一个问题就是当报告问题者大于分派者,或者大于验证者就会出现数据冗余。

所以当只用一个表描述多个多对多关系时,就违背了第四范式,正确的做法如下图:

第五范式

任何满足BCNF范式并且没有复合主键的表将同时满足第五范式。

比如业务需要指定有些工程师只能为某些产品进行服务。

业务还需要了解哪些工程师在为哪些产品服务,以及修复了哪些Bug,下面的设计不符合第五范式

但这个表只说明了这个工程师当前指派去服务哪些产品,它不能说明哪个工程是可以被指派为哪些产品服务

与第四范式一样,也是在一张表中存储多种独立的多对多关系而产生的,微妙的差别是没有null的情况。

bug_id与assigned_to是多对多的关系,assigned_to与product_id是多对多的关系,而bug_id与product_id应该假定是多对一关系存在Bugs表中,每个Bug只属于一个product。

所以解决方案是把每个多对多关系放在一个表中,如下:

DK范式

DK范式涵盖了第三、四、五范式和BCNF范式。并认为表上的每个约束是这张表的数据域约束和主键约束的逻辑结果,如何理解呢?

比如状态为新建的bug应该是没有任何工作时间记录的,也不需要指派验证工程师的,一个做法是在状态这个非主键字段上建立触发器或者check约束,来进行验证如果状态为新建,没有值是允许的,其他情况就不允许。但这种在非主键字段建议此约束的做法不符合DK范式。

第六范式

第六范式目标是消除所有的联结依赖,通常用于支持记录字段取值的变更历史。

如Bug的状态随着时间推移产生变化,任何发生的变更,变更的时间,谁做的变更,以及其他可能的细节,需要另一张表进行记录。

可以想象,如果Bugs这张表需要满足第六范式,则需要变更的列都需要附带一个历史记录表,会导致表的数量过多,多于大多业务来讲,为每列变更都建立一个历史记录表是没有必要的,在一些数据仓库技术中会使用到第六范式。

个人体会:规范是为了减少数据冗余、提高数据的一致性必须的,二、三、四、BCNF、五范式的差异很微妙,随着业务系统的复杂度的提升,需要考虑更高层次的范式。

转载于:https://www.cnblogs.com/bwater/p/8203770.html

数据库设计-规范化规则相关推荐

  1. CCBPM高级开发之类设计与数据库设计命名规则

    总体规则 1,以英文命名,每一个字母大写,提倡用简写.比如Emp 人员 Dept 部门 Station 岗位. 2,如果英文名称太长,或者不常用可考虑用中文命名,建议用中文的缩写.比如管理机关GLJG ...

  2. mysql数据库设计学习---数据库设计规范化的五个要求

    一:表中应该避免可为空的列: 二:表不应该有重复的值或者列: 三: 表中记录应该有一个唯一的标识符  在数据库表设计的时候,数据库管理员应该养成一个好习惯,用一个ID号来 唯一的标识行记录,而不要通过 ...

  3. 数据库设计规范化的5个要求

    通常情况下,可以从两个方面来判断数据库是否设计的比较规范.一是看看是否拥有大量的窄表,二是宽表的数量是否足够的少.若符合这两个条件,则可以说明这个数据库的规范化水平还是比较高的. 当然这是两个泛泛而谈 ...

  4. SQL Server 数据库设计

    一.数据库设计的必要性 在实际的软件项目中,如果系统中需要存储的数据量比较大,需要设计的表比较多,表与表之间的关系比较复杂,那我们就需要进行规范的数据库设置.如果不经过数据库的设计,我们构建的数据库不 ...

  5. 优化MySchool数据库设计(SQL Server)

     优化MySchool数据库设计 学东西要学活学透,用对方能理解的方式讲解(最好以贴近生活的方式讲解)怎么用 编程思维:用空间换时间 项目的开发包括以下几个阶段: 需求分析:分析客户的业务和数据处理需 ...

  6. 【SQL Server】数据库开发指南(一)数据库设计

    文章目录 一.数据库设计的必要性 二.什么是数据库设计 三.数据库设计的重要性 五.数据模型 5.1 实体-关系(E-R)数据模型 5.2 实体(Entity) 5.3 属性(Attribute) 5 ...

  7. 数据库设计五要点 让数据库设计更加规范

    通常情况下,可以从两个方面来判断数据库是否设计的比较规范.一是看看是否拥有大量的窄表,二是宽表的数量是否足够的少.若符合这两个条件,则可以说明这个数据库的规范化水平还是比较高的.当然这是两个泛泛而谈的 ...

  8. 实际项目的数据库设计基本方法

    目录 实际项目的数据库设计基本方法 一. 数据库设计规范化方法 需求分析阶段(常用自顶向下) 概念结构设计阶段(常用自底向上) 逻辑结构设计阶段 物理设计阶段 数据库实施阶段 6.数据库运行和维护阶段 ...

  9. 11 个重要的数据库设计规则

    英文原文: 11 Important Database designing rules 简介 在您开始阅读这篇文章之前,我得明确地告诉您,我并不是一个数据库设计领域的大师.以下列出的 11 点是我对自 ...

最新文章

  1. 利用PHP-ExcelReader实现PHP导入Excel数据[不通过CSV]
  2. SAP 电商云 Spartacus UI delivery mode 页面设计的结构分析
  3. halcon使用点拟合圆形时候,点集顺序紊乱,不影响圆形拟合效果
  4. netflix_Netflix Archaius用于物业管理–基础知识
  5. idea展示runDashboard的窗口
  6. mt4双线macd_【名师讲堂第三季】第六期:基于MACD指标的买卖策略精讲
  7. 程序员是如何处理密码的?
  8. 全向轮机器人特性分析
  9. 【Multisim仿真】10秒倒计时8路抢答器
  10. 微信公众号迁移公证办理流程
  11. Navicat连接不上远程服务器MySQL提示10038
  12. 深入解析Superdome 2:惠普关键业务平台再加强?
  13. 张国荣 - 当爱已成往事
  14. SpringBoot redis GEO 实战应用
  15. 微信支付一 :公众号支付1
  16. 计算机桌面蓝字,电脑桌面上的图标都变成蓝色的了怎么办? – 手机爱问
  17. DS918二合一硬盘安装,配置Oenwrt做软路由
  18. 汽车功能安全 - 危险分析和风险评估
  19. 15 张精美动图全面讲解 CORS
  20. 第八周coreldraw课总结

热门文章

  1. 这些年,NLP常见的预训练模型剖析
  2. 折半查找判定树及平均查找长度
  3. java jpa jar_JPA 开发所需的Jar包 (基于Hibernate)
  4. python怎么数据归一化_基于数据归一化以及Python实现方式
  5. Spring_Bean配置_生命周期_注解
  6. linux中sort命令实例,Linux命令之排序命令sort使用实例
  7. python找不到文件怎么办_python open找不到文件怎么办?
  8. LeetCode 2176. 统计数组中相等且可以被整除的数对
  9. LeetCode 1671. 得到山形数组的最少删除次数(最长上升子序DP nlogn)
  10. LeetCode 742. 二叉树最近的叶节点(建立父节点信息+BFS)