1.概念
设计数据库时,要遵循的一些规范。要遵循后边的范式要求,必须先遵循前边的所有范式要求。
设计关系型数据库时,遵从不同的规范要求,设计出合理的关系型数据库。这些规范被称作范式。越高的范式数据库的冗余度就越低。
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