数据库设计与数据库范式
- UNF
- 1NF:第一范式
- 2NF:第二范式
- 3NF:第三范式
- EKNF
- BCNF:鲍依斯-科得范式
- 4NF:第四范式
- 5NF:第五范式
- DKNF
- 6NF:第六范式
数据库范式(Database Normalization)是指数据库设计的一系列原则和规范,是关系型数据库设计过程中所要遵循的规则和指导方法。数据库范式最早由英国计算机科学家Edgar F. Codd在他的关系数据库模型(Relational model)中提出。
按照规范化程度,数据库范式从低到高依次有:UNF、1NF、2NF、3NF、EKNF、BCNF、4NF、ETNF、5NF、DKNF、6NF。一般实际应用中,最多只会考虑到第四范式(4NF),超出4NF以外的范式一般只出现在学术研究中。
UNF
As a prerequisite to conform to the relational model, a table must have a primary key, which uniquely identifies a row.
即Unnormalized form,最低一级的数据库范式。UNF要求一张表中必须包含主键,以便可以唯一地区分表中的每一行。
1NF:第一范式
Each column of a table must have a single value. Columns which contain sets of values or nested records are not allowed.
第一范式首先必须满足UNF,同时还强调列的原子属性,即一个列不能再被拆分为几个其他的列。
假设有张表的某一列为“紧急联系人”,可以被继续拆分为“紧急联系人姓名”、“紧急联系人联系方式”等几个子列,那么就不满足1NF。
2NF:第二范式
Every non-trivial functional dependency either does not begin with a proper subset of a candidate key or ends with a prime attribute (no partial functional dependencies of non-prime attributes on candidate keys).
第二范式首先必须满足1NF,同时还强调非主键列必须完全依赖主键,要求没有包含在主键中的列必须完全依赖于主键,而不能只依赖于主键的一部分。
假设一张表包含订单号orderID、产品代码productID、产品名称productName、单价unitPrice、折扣discount、数量quantity等多个列,其中主键为(orderID,productID)
。可以发现,discount和quantity与主键中的两列都有依赖关系,但是productName、unitPrice仅取决于productID。因此不满足2NF,容易产生冗余数据。
解决的办法是把上面的表拆分为两张表,第一张表包含[orderID, productID, discount, quantity]
,另一张表包含[productID, unitPrice, productName]
。
3NF:第三范式
Every non-trivial functional dependency either begins with a superkey or ends with a prime attribute (no transitive functional dependencies of non-prime attributes on candidate keys).
第三范式首先必须满足2NF,同时还强调非主键列必须直接依赖于主键列,不能存在依赖传递。即不能存在一个非主键列A依赖于另一个非主键列B,然后非主键列B再依赖于主键的情况。
假设一张表中存在书名title、作者author、作者国籍authorNationality、品类代码genreID、品类名称genreName、页数pages等多个列,其中主键为title
。可以发现,authorNationality列取决于author列,而author列取决于主键title列;同时,genreName取决于genreID,而genreID取决于主键title。即存在依赖传递现象,因此不满足3NF。
解决办法是把上面的表拆分为三张表,第一张包含[title, author, genreID, pages]
,第二张表包含[author, authorNationality]
,第三张表包含[genreID, genreName]
。
EKNF
Every non-trivial functional dependency either begins with a superkey or ends with an elementary prime attribute.
即Elementary-key Normal Form,介于3NF和BCNF之间。EKNF一般很少被提到。
BCNF:鲍依斯-科得范式
Every non-trivial functional dependency begins with a superkey.
A relational schema R is in Boyce–Codd normal form if and only if for every one of its dependencies X → Y, at least one of the following conditions hold:
(1) X → Y is a trivial functional dependency (Y ⊆ X).
(2) X is a superkey for schema R.
即Boyce-Codd Normal Form,又被称为3.5NF。BCNF在满足3NF的基础上,还强调主键的某一列不能依赖于主键的其他列。
假设一张库存表中有仓库名warehouse、管理员名keeper、商品名article、数量quantity几个列。其中主键为(warehouse, keeper, article)
。可以发现,keeper是依赖于warehouse的,删除某一个仓库也会导致同时删除管理员,因此不符合BCNF。
考虑另一个例子,有一张网球场预约记录表,包含球场编号court、预约开始时间startTime,预约结束时间endTime、预约类型rateType等多个列。预约类型可以分为以下四类:
- SAVER:会员预定、场地1;
- STANDARD:非会员预定、场地1;
- PREMIUM-A:会员预定、场地2;
- PREMIUM-B:非会员预定、场地2。
主键(court, startTime, endTime, rateType)
可以唯一地标识每一行。但是主键列rateType部分依赖于另一个主键列court,同时主键列court完全依赖于另一个主键列rateType,因此不满足BNCF。
解决办法是把上面的表拆分为两张表,一张表包含[court, startTime, endTime, memberFlag]
,另一张表包含[rateType, court, memberFlag]
。其中memberFlag列用来标识预约者是否为会员身份。
4NF:第四范式
Every non-trivial multivalued dependency begins with a superkey.
4NF在满足BCNF的基础上,还强调非主键属性不应该有多值。前面介绍的2NF、3NF和BCNF都只考虑了函数依赖(functional dependencies),第四范式则是考虑了多值依赖(multivalued dependency)。4NF限制关系模式的属性间不允许有非平凡(non-trivial)且非函数依赖的多值依赖。
假设有这样一张表,记录了各个餐厅可以往不同区域外卖派送的披萨种类,包含[restaurant, pizzaVariety, deliveryArea]
多个列。候选键(restaurant, pizzaVariety, deliveryArea)
可以唯一地标识每一行,且列之间不存在决定关系,因此该表满足BCNF。
如果餐厅可以往所有区域派送所有的披萨种类,那么上面的表不满足4NF,存在数据冗余。因为restaurant分别与pizzaVariety和deliveryArea之间存在非平凡的多值依赖,但restaurant本身不能构成一个超键。例如,如果某个餐厅新出了一种披萨口味,需要往表里添加多行(因为有多个区域)。
解决的办法是把上面的表拆分为两张表,第一张包含[restaurant, pizzaVariety]
,另一张包含[restaurant, deliveryArea]
。
5NF:第五范式
Every join dependency has only superkey components.
5NF在满足4NF的基础上,还要求表必须可以分解为较小的表,除非那些表在逻辑上拥有与原始表相同的主键。
如果只考虑函数依赖,关系模式规范化程度最高的范式是BCNF;如果考虑多值依赖,则是4NF。如果在第四范式的基础上,消除了4NF中存在的连接依赖,则可以满足5NF。
考虑这样一张表,包含了销售人员salesman、代销品牌brand、产品类型productType多个列,主键为(salesman, brand, productType)
。假设某个产品有多个品牌都在生产,销售在代理该产品类型时,必须同时代理所有品牌的该产品,那么这个表可以被分解为以下三个小表:第一张表包含[salesman, productType]
,第二张表包含[salesman, brand]
,第三张表包含[brand, productType]
。
注:一般实际应用中不必考虑第五范式。
DKNF
Every constraint is a consequence of domain constraints and key constraints.
即Domain-key Normal Form。DKNF在满足5NF的基础上,还要求数据库只包含域约束(domain constraints)和键约束(key constraints)两种约束类型。域约束是指限制列属性可以取值的范围;键约束则是指可以通过某些属性唯一地标识每一行数据。
考虑一张表,包含富人wealthyPeople、富人类型personType、财富值netWorth多个列,其中personType根据财富值可以划分为Millionaire和Billionaire。可以发现,personType与netWorth列之间存在约束关系,但既不是键约束、也不是域约束关系。
因此可以将这种表拆分为两张表,第一张包含[wealthyPeople, netWorth]
,第二张包含[personType, minWorth, maxWorth]
。其中maxWorth和minWorth分别表示百万富翁、亿万富翁应当具有的财富值上下限。
6NF:第六范式
Every join dependency is trivial.
对6NF的一个简单直白的描述就是:如果一张表的行只包含主键、以及最多一个其他列,即满足6NF。
例如,一张表包含[publisherID, publisherName, country]
三列,其中publisherID为主键。为满足6NF,需要将其拆分为两张表,一张包含[publihserID, publisherName]
,另一张包含[publihserID, country]
。
注:一般实际应用中不必考虑第六范式。
References Database Normalization