数据库范式重温总结

第一范式(1NF)

属性不可再分,强调的是原子性。
如表:【联系人】(姓名,性别,电话),在实际场景中,联系人有家庭电话和公司电话,那么这种表结构设计就没有达到 1NF。要符合 1NF 我们只需把列(电话)拆分,即:【联系人】(姓名,性别,家庭电话,公司电话)。

第二范式(2NF)

首先,符合1NF,并且,非主属性完全依赖于码,即没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。强调的是完全依赖而非部分依赖。
考虑一个订单明细表:【OrderDetail】(OrderID,ProductID,UnitPrice,Discount,Quantity,ProductName)。
因为我们知道在一个订单中可以订购多种产品,所以单单一个 OrderID 是不足以成为主键的,主键应该是(OrderID,ProductID)。显而易见 Discount(折扣),Quantity(数量)完全依赖(取决)于主键(OderID,ProductID),而 UnitPrice,ProductName 只依赖于 ProductID。所以 OrderDetail 表不符合 2NF。不符合 2NF 的设计容易产生冗余数据。
可以把【OrderDetail】表拆分为【OrderDetail】(OrderID,ProductID,Discount,Quantity)和【Product】(ProductID,UnitPrice,ProductName)来消除原订单表中UnitPrice,ProductName多次重复的情况。

第三范式(3NF)

首先,符合 2NF,另外非主键列必须直接依赖于主键,不能存在传递依赖。即不能存在:非主键列 A 依赖于非主键列 B,非主键列 B 依赖于主键的情况。 强调的是消除传递依赖。
考虑一个订单表【Order】(OrderID,OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity)主键是(OrderID)。
其中 OrderDate,CustomerID,CustomerName,CustomerAddr,CustomerCity 等非主键列都完全依赖于主键(OrderID),所以符合 2NF。不过问题是 CustomerName,CustomerAddr,CustomerCity 直接依赖的是 CustomerID(非主键列),而不是直接依赖于主键,它是通过传递才依赖于主键,所以不符合 3NF。
通过拆分【Order】为【Order】(OrderID,OrderDate,CustomerID)和【Customer】(CustomerID,CustomerName,CustomerAddr,CustomerCity)从而达到 3NF。

BC范式(BCNF)

任何字段都不能传递依赖任一侯选关键字。第三范式为非主键列不能传递依赖,而BC范式为所有键列都不能传递依赖。在第三范式的基础上,进一步消除了主属性的传递依赖。BC范式既检查非主属性,又检查主属性。

第四范式(4CF)

把同一表内的多对多关系删除。

第五范式(5CF)

从最终结构重新建立原始结构。

正确认识数据冗余

主键与外键在多表中的重复出现, 不属于数据冗余,这个概念必须清楚。非键字段的重复出现, 才是数据冗余!而且是一种低级冗余,即重复性的冗余。高级冗余不是字段的重复出现,而是字段的派生出现。
例:商品中的“单价、数量、金额”三个字段,“金额”就是由“单价”乘以“数量”派生出来的,它就是冗余,而且是一种高级冗余。冗余的目的是为了提高处理速度。只有低级冗余才会增加数据的不一致性,因为同一数据,可能从不同时间、地点、角色上多次录入。

总结

绝大多数实际开发最多用到BC范式。第四和第五范式感兴趣多看看资料,了解即可。范式不是越高越好,过于范式化会对数据库的逻辑可读性和使用效率起到阻碍。
数据库连接有性能消耗,实际开发过程中,会有数据冗余,以空间换时间,所以提倡高级冗余(派生性冗余),反对低级冗余(重复性冗余)。

其他

执行sql语句前,首先将数据从硬盘加载到数据缓冲区。
mysql语句执行顺序如下,from最先执行,limit最后执行,每一个操作都会产生一张虚拟表,产生的虚拟表作为下一个处理的输入,除最后一张虚拟表作为结果返回,其他中间虚拟表对用户是透明的。

1
2
3
4
5
6
7
8
9
10
11
(1)from
(3)join
(2)on
(4)where
(5)group by
(6)avg,sum....
(7)having
(8)select
(9)distinct
(10)order by
(11)limit