数据库设计的范式

1.概念

设计数据库时,要遵循的一些规范。要遵循后边的范式要求,必须先遵循前边的所有范式要求。

设计关系型数据库时,遵从不同的规范要求,设计出合理的关系型数据库。这些规范被称作范式。越高的范式数据库的冗余度就越低。

关系数据库中的关系必须满足一定的要求,即满足不同的范式。
关系数据库有六种范式:第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴德斯科范式(BCNF)、第四范式(4NF)和第五范式(5NF)。
满足最低要求的范式是第一范式(1NF)。
在第一范式的基础上进一步满足更多要求的称为第二范式(2NF),其余范式以次类推。
一般说来,数据库只需满足第三范式(3NF)就行了。

2.分类

  • 第一范式(1NF):无重复的列,数据库表的每一列都是不可分割的原子数据项,而不能是集合,数组,记录等非原子数据项。如果实体中的某个属性有多个值时,必须拆分为不同的属性
  • 第二范式(2NF):每张表只描述一件事情,

    前提:满足第一范式
    在第一范式的基础上,非码属性必须完全依赖于候选码(在第一范式的基础上消除非主属性对主码的部分函数依赖)
    第二范式需要确保数据库表中每一列都和主键相关,而不能只与主键的某一部分相关(主要针对主键而言)。

  • 第三范式(3NF):与主键直接相关,不得间接相关

3.为什么需要设计

当数据库比较复杂的时候,就需要设计
糟糕的数据库设计

  • 数据冗余,浪费空间
  • 数据插入和删除都比较麻烦,且容易产生异常【屏蔽使用物理外键】
  • 程序的性能差

良好的数据库设计:

  • 节省内存空间
  • 保证数据的完整性
  • 方便我们开发系统

软件开发中,关于数据库的设计

  • 分析需求:分析业务和需要处理的数据库的需求
  • 概要设计:设计关系图E-R

设计数据库的步骤:(以个人博客为例)

  • 收集信息,分析需求
    • 用户表(用户登录注销,用户的个人信息,写博客,创建分类)
    • 分类表(文章分类,谁创建的)
    • 文章表(文章的信息)
    • 评论表
    • 友情链接表(友情连接信息)
    • 自定义表(系统信息,某个关键字,或者一些主字段) key:value
  • 标识实体类(把需求落地到每个字段)
  • 标识实体之间的关系
    • 写博客:user --> blog
    • 博客分类:user --> category
    • 关注:user --> user
    • 友链:links
    • 评论:user-user-blog

4.三大范式详解

为什么需要数据规范化?

  • 信息重复
  • 更新异常
  • 插入异常
    • 无法正常显示信息
  • 删除异常
    • 丢失有效的信息

(1)第一范式:保证每一列不可再分

要求数据库表的每一列都是不可分割的原子数据项。
原子性:保证每一列不可再分

 

 在上面的表中,“家庭信息”和“学校信息”列均不满足原子性的要求,故不满足第一范式,调整如下:

 

下表“系”这一列也是可以分割的,不满足第一范式

改成这样,就符合第一范式了

 不过这个数据还存在其他问题:

  • 存在非常严重的冗余(重复):姓名,系名,系主任
  • 数据添加存在问题:添加新开设的系和系主任时,数据不合法,(还没招收学生)

  • 数据删除存在问题:张无忌同学毕业了,删除数据,会将系的数据一起删除

(2)第二范式:每张表只描述一件事情

前提:满足第一范式
在第一范式的基础上,非码属性必须完全依赖于候选码在第一范式的基础上消除非主属性对主码的部分函数依赖
第二范式需要确保数据库表中每一列都和主键相关,而不能只与主键的某一部分相关(主要针对主键而言)。

几个概念:

函数依赖

  • A-->B,如果通过A属性(属性组)的值,可以确定唯一B属性的值,则称B依赖于A

例如:学号-->姓名(序号被姓名所依赖),但是学号不被分数所依赖,因为学号+课程名称,才能确定分数,即:(学号,课程名称)--> 分数

  • 完全函数依赖:A --> B,如果A是一个属性组,则B属性值的确定需要依赖于A属性组中所有的属性值。

例如:学号和课程名称被分数完全依赖

  • 部分函数依赖:A --> B,如果A是一个属性组,则B属性值的确定只需要依赖于A属性组中的一些值即可。

例如:(学号,课程名称)--> 姓名

  • 传递函数依赖:A --> B,B --> C,如果通过A属性(属性组)的值,可以确定唯一B属性的值,在通过B属性(属性组)的值可以确定唯一C属性的值,则称C传递函数依赖于A

例如:学号被系名依赖,系名被系主任依赖,学号 --> 系名,系名 --> 系主任

  • :如果在一张表中,一个属性或属性组,被其他所有属性所完全依赖,则称这个属性(属性组)为该表的码

 例如:该表中的码为:(学号,课程名称)

  • 主属性:码属性组中的所有属性
  • 非主属性:除过码属性组的属性

系名,系主任是只依赖于学号,因此对于码(学号,课程名称)来说是部分依赖,分数是完全依赖于码(学号,课程名称)

 再来看一下,第二范式的定义:在第一范式的基础上消除非主属性对主码的部分函数依赖

 我们改造上面的表

 这样就消除了原来的表中部分依赖

第一张表,分数就是非主属性

第二张表,姓名,系名,系主任都是非主属性

这样,上面存在的三个问题,第一个问题可以解决,剩下两个问题:

  • 存在非常严重的冗余(重复):姓名,系名,系主任
  • 数据添加存在问题:添加新开设的系和系主任时,数据不合法

  • 数据删除存在问题:张无忌同学毕业了,删除数据,会将系的数据一起删除

(3)第三范式:与主键直接相关,不得间接相关

 在2NF基础上,属性不能传递依赖于主属性(属性不依赖于其它非主键属性),即在2NF基础上消除传递依赖

第三范式需要确保数据表中的每一列数据都和主键直接相关,不能间接相关

我们在学生表中发现,学号被系名依赖,系主任依赖于系名,这样就存在传递依赖,系主任传递依赖于学号,因此要消除这样的传递依赖

 因此我们再来分出一张系表

 

再来看刚才的三个问题:

  • 存在非常严重的冗余(重复):姓名,系名,系主任
  • 数据添加存在问题:添加新开设的系和系主任时,数据不合法

 新开的系和系主任,这个数据是合法的(这样就不管还有没有招收学生)。

  • 数据删除存在问题:张无忌同学毕业了,删除数据,会将系的数据一起删除

 

 删除张无忌这个学生的信息,不影响系名和系主任的信息

 刚刚三个问题被全部解决掉了。

 在以后的数据库设计过程中,可以使用这三大范式验证这个数据库设计是否合理

5.规范性和性能的问题

关联查询的表不得超过三张表

  • 考虑商业化的需求和目标,(成本,用户体验) 数据库的性能更加重要
  • 在规范性能的问题的时候,需要适当考虑一下规范性!
  • 故意给某些表增加一些冗余的字段(从夺标查询中变成单表查询)
  • 故意增加一些计算列(每次增加自动加1,从大数据量降低为小数据量查询)

参考:http://3ms.huawei.com/km/blogs/details/9252227?l=zh-cn

posted @ 2020-12-07 14:42  GumpYan  阅读(243)  评论(2编辑  收藏  举报