数据库表设计
# 范式设计
第一范式(1NF)、第二范式(2NF)、第三范式(3NF)、巴斯-科德范式(BCNF)、第四范式(4NF)和第五范式(5NF,又称完美范式)。一级比一级要求得严格。
# 第一范式
- 定义: 属于第一范式关系的所有属性都不可再分,即数据项不可分。
- 理解: 第一范式强调数据表的原子性,是其他范式的基础,列不可再分。
- 例子: name-age列具有两个属性,一个name,一个 age不符合第一范式,把它拆分成两列
# 第二范式
- 要求: 满足第二范式(2NF)必须先满足第一范式(1NF)
- 定义: 数据库表中的每个实例或行必须可以被惟一地区分;实体的属性完全依赖于主关键字
- 理解:需要为表加上主键,不能存在联和主键
- 例子: 订单表(订单id和产品id保证唯一),产品表 =》 订单表,产品表,订单与商品的中间表
# 第三范式
- 要求: 满足第三范式(3NF)必须先满足第二范式(2NF)
- 定义: 每一个非主属性既不部分依赖于也不传递依赖于业务主键,也就是在第二范式的基础上消除了非主键对主键的传递依赖.
- 理解: 把大量的数据冗余,单独用张表分离出来,通过关联来存储。
- 例子: 学生表(学号id,姓名,年龄,性别,系别,系办地址、系办电话) ; 系别相关信息会出现冗余,所以应该改成学生表和系别表。
# 其余范式
看情况满足,一般做到上面的就行了。
# 反范式设计
完全符合范式化的设计真的完美无缺吗?很明显在实际的业务查询中会大量存在着表的关联查询,而大量的表关联很多的时候非常影响查询的性能。
所谓得反范式化就是为了性能和读取效率得考虑而适当得对数据库设计范式得要求进行违反。允许存在少量得冗余,换句话来说反范式化就是使用空间来换取时间。
# 示例
- 范式化设计: 商品信息、分类信息表、分类和商品对应表
- 业务中,商品信息和分类信息经常一起查询,3表关联性能快不??
- 反范式化设计 : 所以把分类信息也放到商品表里面,冗余存放。
# 反范式实现
- 缓存表,mysql把一些复杂的sql结果存到临时表
- 汇总表,统计的临时表。
- 计数器表,计算的临时表。
- 分库分表中的查询,生成买家和卖家2个副本信息,各自查询各自的表以提交性能。
# 范式化和反范式总结
# 范式化优点
1、范式化的更新操作通常比反范式化要快。
2、当数据较好地范式化时,就只有很少或者没有重复数据,所以只需要修改更少的数据。
3、范式化的表通常更小,可以更好地放在内存里,所以执行操作会更快。
4、很少有多余的数据意味着检索列表数据时更少需要DISTINCT或者GROUP BY语句。在非范式化的结构中必须使用DISTINCT或者GROUPBY才能获得一份唯一的列表,但是如果是一张单独的表,很可能则只需要简单的查询这张表就行了。
# 范式化缺点
- 范式化设计的缺点是通常需要关联。稍微复杂一些的查询语句在符合范式的表上都可能需要至少一次关联,也许更多。
- 这不但代价昂贵,也可能使一些索引策略无效。
- 例如,范式化可能将列存放在不同的表中,而这些列如果在一个表中本可以属于同一个索引。
# 反范式化设计优点
- 反范式设计可以减少表的关联
- 可以更好的进行索引优化。
# 反范式化设计缺点
- 存在数据冗余及数据维护异常
- 对数据的修改需要更多的成本
# 参考资料
六种范式有不错的例子。
假设仓库管理关系表为StorehouseManage(仓库ID,存储物品ID,管理员ID,数量),且有一个管理员只在一个仓库工作;一个仓库可以存储多种物品。这个数据库表中存在如下决定关系:
(仓库ID,存储物品ID) →(管理员ID,数量)
(管理员ID,存储物品ID) → (仓库ID,数量)
所以,(仓库ID,存储物品ID)和(管理员ID,存储物品ID)都是StorehouseManage的候选关键字,表中的唯一非关键字段为数量,它是符合第三范式的。但是,由于存在如下决定关系:
(仓库ID) → (管理员ID)
(管理员ID) → (仓库ID)
即存在关键字段决定关键字段的情况,所以其不符合BCNF范式。它会出现如下异常情况:
(1) 删除异常:
当仓库被清空后,所有"存储物品ID"和"数量"信息被删除的同时,"仓库ID"和"管理员ID"信息也被删除了。
(2) 插入异常:
当仓库没有存储任何物品时,无法给仓库分配管理员。
(3) 更新异常:
如果仓库换了管理员,则表中所有行的管理员ID都要修改。
把仓库管理关系表分解为二个关系表:
仓库管理:StorehouseManage(仓库ID,管理员ID);
仓库:Storehouse(仓库ID,存储物品ID,数量)。
这样的数据库表是符合BCNF范式的,消除了删除异常、插入异常和更新异常。