数据库范式

关系表设计模式

键与属性


  • 超键(Super Key):能唯一确定一条记录的属性集
  • 候选键(Candidate Key):不含多余属性的超键,删除任一属性都不能唯一标识
  • 主键(Primary Key):选择出的一组候选键
  • 主属性:参与到候选键中的属性

1NF


字段原子性,不可再分,应具有主键

反例

人和喜爱的水果,水果分开存

1
2
3
4
5
-------------------------------
| Name | Fruits |
-------------------------------
| Alice | Apple,Banana,Mango |
-------------------------------

2NF


非键数据对主键完全依赖,不能部分依赖候选键

反例

水果价格表,水果ID和商店ID都作为主键
价格跟水果和商店都有关,但是商店名跟水果无关
这种设计后果是同一店铺增加水果,也要带上商店名

1
2
3
4
5
---------------------------------------------
| Fruit Id | Shop Id | Shop Name | Price |
---------------------------------------------
| 1 | 1 | Super Market | 20 |
---------------------------------------------

3NF


非键字段间没有依赖关系

反例

水果订单表,总价依赖单价和数量,可以计算出来,而单价和数量依赖订单Id,构成传递

1
2
3
4
5
--------------------------------------------------------
|Order Id| Fruit Id | Shop Id | Price | Amount | Total |
--------------------------------------------------------
| 1 | 1 | 1 | 20 | 2 | 40 |
--------------------------------------------------------

BCNF


任何数据都不能传递依赖任一候选键,候选键之间有依赖也不行

反例

(订单号)和(日期,序号)都是候选键,订单号依赖于日期和序号

1
2
3
4
5
-------------------------------------------------------------------------
| Order Id | Date | Serial Number | Fruit Id | Price | Amount |
-------------------------------------------------------------------------
| 20170801001 | 20170801 | 001 | 1 | 20 | 2 |
-------------------------------------------------------------------------

4NF


多值依赖

反例

水果配送表,三个属性共同作为主键
每家店供应多种水果,每家店配送多个地区,这些值是确定的
店铺决定了水果范围和地区范围,但是店铺能供应的水果和配送地区之间无关,这是多值依赖
这种设计后果是增加水果或者配送范围,都要插入多条记录,单独拆分成店铺水果表和店铺配送表比较好

1
2
3
4
5
--------------------------------------
| Shop Id | Fruit Id | Delivery Area |
--------------------------------------
| 1 | 1 | A |
--------------------------------------

范式化


优点

  • 减少冗余,节省了存储空间
  • 减少不必要的更新,更新通常只需要更新一个地方,增进数据一致性,提升写性能

代价

  • 增加了Join操作,读性能下降

范式化结构可以DBMS视图来降低Join开销

反范式化


磁盘空间成本低,允许一定冗余,减少Join,加速读取

原则


  • 不变的数据即使冗余也不会有更新一致性问题,不需要规范化
  • 反范式化应该在范式的基础上进行局部调整,而不是放弃范式化