草庐IT

关系型数据库设计三大范式

Jcloud 2023-03-28 原文

作者:郑龙飞

范式定义

百度百科:设计关系数据库时,遵从不同的规范要求,设计出合理的关系型数据库,这些不同的规范要求被称为不同的范式,各种范式呈递次规范,越高的范式数据库冗余越小。

人类语言: 范式可以理解为设计一张数据表的表结构,符合的标准级别、规范和要求。

而通常我们用的最多的就是第一范式(1NF)、第二范式(2NF)、第三范式(3NF),也就是本文要讲的“三大范式”。

范式的优点

采用范式可以降低数据的冗余性。

为什么要降低数据的冗余性?

  1. 十几年前,磁盘很贵,为了减少磁盘存储。
  2. 以前没有分布式系统,都是单机,只能增加磁盘,磁盘个数也是有限的。
  3. 一次修改,需要修改多个表,很难保证数据一致性。

范式的缺点

范式的缺点是获取数据时,需要通过Join拼接出最后的数据。

目前范式的分类

目前业界范式有:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)、第五范式(5NF)。

什么是函数依赖?

百度百科:函数依赖简单点说就是:某个属性集决定另一个属性集时,称另一属性集依赖于该属性集。

人类语言:以下面表格为例,通俗易懂的解释,什么是函数依赖。

学号 姓名 系名 系主任 科名 分数
001 张三 计算机系 李雷 高等数学 87
001 张三 计算机系 李雷 大学英语 88
001 张三 计算机系 李雷 数据库设计 89
002 李四 计算机系 李雷 高等数学 86
002 李四 计算机系 李雷 java程序设计 90
002 李四 计算机系 李雷 大学英语 98
003 王五 财务系 韩梅梅 高等数学 96
003 王五 财务系 韩梅梅 财务基础 95

完全函数依赖

官方定义:设X,Y是关系R的两个属性集合,X’是X的真子集,存在X→Y,但对每一个X’都有X’!→Y,则称Y完全函数依赖于X。

人类语言:比如通过,(学号,课程) 推出分数 ,但是单独用学号推断不出来分数,那么就可以说:分数 完全依赖于(学号,课程) 。

总结:即:通过A B能得出C,但 是A B单独得不出C,那么说C完全依赖于AB。

部分函数依赖

官方定义:假如 Y函数依赖于 X,但同时 Y 并不完全函数依赖于 X,那么我们就称 Y 部分函数依赖于 X。

人类语言:比如通过,(学 号,课程) 推出姓名,因为其实直接可以通过,学号推出姓名,所以:姓名 部分依赖于 (学号,课程)。

总结:通过AB能得出C,通过A也能得出C,或者通过B也能得出C,那么说C部分依赖于AB。

传递函数依赖

官方定义:传递函数依赖:设X,Y,Z是关系R中互不相同的属性集合,存在X→Y(Y !→X),Y→Z,则称Z传递函数依赖于X。

人类语言:比如:学号 推出 系名 , 系名 推出 系主任, 但是,系主任推不出学号,系主任主要依赖于系名。这种情况可以说:系主任 传递依赖于 学号 。

总结:即:通 过A得 到B,通 过B得 到C,但 是C得不到A,那 么说C传递依赖于A。

三范式的区别

第一范式

第一范式1NF核心原则:属性不可切割。

举例说明:

学号 姓名 系名 系主任 科名 分数 学籍信息
001 张三 计算机系 李雷 高等数学 87 本科,大二
002 李四 计算机系 李雷 大学英语 88 研究生,研三

很明显上面表格设计是不符合第一范式的,学籍信息列中的数据不是原子数据项,是可以进行分割的,因此对表格进行修改,让表格符合第一范式的要求,修改结果如下图所示:

学号 姓名 系名 系主任 科名 分数 学历 所在年级
001 张三 计算机系 李雷 高等数学 87 本科 大二
002 李四 计算机系 李雷 大学英语 88 研究生 研三

实际上 ,1NF是所有关系型数据库的最基本要求 ,你在关系型数据库管理系统(RDBMS),例如SQL Server,Oracle,MySQL中创建数据表的时候,如果数据表的设计不符合这个最基本的要求,那么操作一定是不能成功的。也就是说,只要在RDBMS中已经存在
的数据表,一定是符合1NF的。

第二范式

第二范式2NF核心原则:不能存在“部分函数依赖”。

举例说明:

学号 姓名 系名 系主任 科名 分数
001 张三 计算机系 李雷 高等数学 87
001 张三 计算机系 李雷 大学英语 88
001 张三 计算机系 李雷 数据库设计 89
002 李四 计算机系 李雷 高等数学 86
002 李四 计算机系 李雷 java程序设计 90
002 李四 计算机系 李雷 大学英语 98
003 王五 财务系 韩梅梅 高等数学 96
003 王五 财务系 韩梅梅 财务基础 95

以上表格明显存在,部分依赖。比 如,这张表的主键是 (学号,课名),分数确实完全依赖于(学号,课名),但是姓名并不完全依赖于(学号,课名),让表格符合第二范式的要求,修改结果如下图所示:

学号 科名 分数
001 高等数学 87
001 大学英语 88
001 数据库设计 89
002 高等数学 86
002 java程序设计 90
002 大学英语 98
003 高等数学 96
003 财务基础 95
学号 姓名 系名 系主任
001 张三 计算机系 李雷
002 李四 计算机系 李雷
003 王五 财务系 韩梅梅

以上符合第二范式,去掉部分函数依赖依赖。

第三范式

第三范式 3NF核心原则:不能存在传递函数依赖。

举例说明:

学号 姓名 系名 系主任
001 张三 计算机系 李雷
002 李四 计算机系 李雷
003 王五 财务系 韩梅梅

在上面这张表中,存 在传递函数依赖:学号->系 名->系主任,但是系主任推不出学号。

上面表需要再次拆解:

学号 姓名 系名
001 张三 计算机系
002 李四 计算机系
003 王五 财务系
系名 系主任
计算机系 李雷
计算机系 李雷
财务系 韩梅梅

反三范式

没有冗余的数据库未必是最好的数据库,有时为了提高运行效率,就必须降低范式标准,适当保留冗余数据。具体做法是: 在概念数据模型设计时遵守第三范式,降低范式标准的工作放到物理数据模型设计时考虑。降低范式就是增加字段,减少了查询时的关联,提高查询效率,因为在数据库的操作中查询的比例要远远大于DML的比例。但是反范式化一定要适度,并且在原本已满足三范式的基础上再做调整的。

总结

引用知乎大佬对范式的理解:

数据库设计应该也是分为三个境界的:

第一个境界,刚入门数据库设计,范式的重要性还未深刻理解。这时候出现的反范式设计,一般会出问题。

第二个境界,随着遇到问题解决问题,渐渐了解到范式的真正好处,从而能快速设计出低冗余、高效率的数据库。

第三个境界,再经过N年的锻炼,是一定会发觉范式的局限性的。此时再去打破范式,设计更合理的反范式部分。

有关关系型数据库设计三大范式的更多相关文章

  1. ruby-on-rails - Rails - 子类化模型的设计模式是什么? - 2

    我有一个模型:classItem项目有一个属性“商店”基于存储的值,我希望Item对象对特定方法具有不同的行为。Rails中是否有针对此的通用设计模式?如果方法中没有大的if-else语句,这是如何干净利落地完成的? 最佳答案 通常通过Single-TableInheritance. 关于ruby-on-rails-Rails-子类化模型的设计模式是什么?,我们在StackOverflow上找到一个类似的问题: https://stackoverflow.co

  2. ruby - 解析 RDFa、微数据等的最佳方式是什么,使用统一的模式/词汇(例如 schema.org)存储和显示信息 - 2

    我主要使用Ruby来执行此操作,但到目前为止我的攻击计划如下:使用gemsrdf、rdf-rdfa和rdf-microdata或mida来解析给定任何URI的数据。我认为最好映射到像schema.org这样的统一模式,例如使用这个yaml文件,它试图描述数据词汇表和opengraph到schema.org之间的转换:#SchemaXtoschema.orgconversion#data-vocabularyDV:name:namestreet-address:streetAddressregion:addressRegionlocality:addressLocalityphoto:i

  3. ruby-on-rails - 使用 rails 4 设计而不更新用户 - 2

    我将应用程序升级到Rails4,一切正常。我可以登录并转到我的编辑页面。也更新了观点。使用标准View时,用户会更新。但是当我添加例如字段:name时,它​​不会在表单中更新。使用devise3.1.1和gem'protected_attributes'我需要在设备或数据库上运行某种更新命令吗?我也搜索过这个地方,找到了许多不同的解决方案,但没有一个会更新我的用户字段。我没有添加任何自定义字段。 最佳答案 如果您想允许额外的参数,您可以在ApplicationController中使用beforefilter,因为Rails4将参数

  4. ruby - Ruby 有 `Pair` 数据类型吗? - 2

    有时我需要处理键/值数据。我不喜欢使用数组,因为它们在大小上没有限制(很容易不小心添加超过2个项目,而且您最终需要稍后验证大小)。此外,0和1的索引变成了魔数(MagicNumber),并且在传达含义方面做得很差(“当我说0时,我的意思是head...”)。散列也不合适,因为可能会不小心添加额外的条目。我写了下面的类来解决这个问题:classPairattr_accessor:head,:taildefinitialize(h,t)@head,@tail=h,tendend它工作得很好并且解决了问题,但我很想知道:Ruby标准库是否已经带有这样一个类? 最佳

  5. ruby - Rails 关联 - 同一个类的多个 has_one 关系 - 2

    我的问题的一个例子是体育游戏。一场体育比赛有两支球队,一支主队和一支客队。我的事件记录模型如下:classTeam"Team"has_one:away_team,:class_name=>"Team"end我希望能够通过游戏访问一个团队,例如:Game.find(1).home_team但我收到一个单元化常量错误:Game::team。谁能告诉我我做错了什么?谢谢, 最佳答案 如果Gamehas_one:team那么Rails假设您的teams表有一个game_id列。不过,您想要的是games表有一个team_id列,在这种情况下

  6. ruby - 我如何添加二进制数据来遏制 POST - 2

    我正在尝试使用Curbgem执行以下POST以解析云curl-XPOST\-H"X-Parse-Application-Id:PARSE_APP_ID"\-H"X-Parse-REST-API-Key:PARSE_API_KEY"\-H"Content-Type:image/jpeg"\--data-binary'@myPicture.jpg'\https://api.parse.com/1/files/pic.jpg用这个:curl=Curl::Easy.new("https://api.parse.com/1/files/lion.jpg")curl.multipart_form_

  7. 世界前沿3D开发引擎HOOPS全面讲解——集3D数据读取、3D图形渲染、3D数据发布于一体的全新3D应用开发工具 - 2

    无论您是想搭建桌面端、WEB端或者移动端APP应用,HOOPSPlatform组件都可以为您提供弹性的3D集成架构,同时,由工业领域3D技术专家组成的HOOPS技术团队也能为您提供技术支持服务。如果您的客户期望有一种在多个平台(桌面/WEB/APP,而且某些客户端是“瘦”客户端)快速、方便地将数据接入到3D应用系统的解决方案,并且当访问数据时,在各个平台上的性能和用户体验保持一致,HOOPSPlatform将帮助您完成。利用HOOPSPlatform,您可以开发在任何环境下的3D基础应用架构。HOOPSPlatform可以帮您打造3D创新型产品,HOOPSSDK包含的技术有:快速且准确的CAD

  8. FOHEART H1数据手套驱动Optitrack光学动捕双手运动(Unity3D) - 2

    本教程将在Unity3D中混合Optitrack与数据手套的数据流,在人体运动的基础上,添加双手手指部分的运动。双手手背的角度仍由Optitrack提供,数据手套提供双手手指的角度。 01  客户端软件分别安装MotiveBody与MotionVenus并校准人体与数据手套。MotiveBodyMotionVenus数据手套使用、校准流程参照:https://gitee.com/foheart_1/foheart-h1-data-summary.git02  数据转发打开MotiveBody软件的Streaming,开始向Unity3D广播数据;MotionVenus中设置->选项选择Unit

  9. 使用canal同步MySQL数据到ES - 2

    文章目录一、概述简介原理模块二、配置Mysql使用版本环境要求1.操作系统2.mysql要求三、配置canal-server离线下载在线下载上传解压修改配置单机配置集群配置分库分表配置1.修改全局配置2.实例配置垂直分库水平分库3.修改group-instance.xml4.启动监听四、配置canal-adapter1修改启动配置2配置映射文件3启动ES数据同步查询所有订阅同步数据同步开关启动4.验证五、配置canal-admin一、概述简介canal是Alibaba旗下的一款开源项目,Java开发。基于数据库增量日志解析,提供增量数据订阅&消费。Git地址:https://github.co

  10. ruby-on-rails - 创建 ruby​​ 数据库时惰性符号绑定(bind)失败 - 2

    我正在尝试在Rails上安装ruby​​,到目前为止一切都已安装,但是当我尝试使用rakedb:create创建数据库时,我收到一个奇怪的错误:dyld:lazysymbolbindingfailed:Symbolnotfound:_mysql_get_client_infoReferencedfrom:/Library/Ruby/Gems/1.8/gems/mysql2-0.3.11/lib/mysql2/mysql2.bundleExpectedin:flatnamespacedyld:Symbolnotfound:_mysql_get_client_infoReferencedf

随机推荐