SQL 范式(转载)

装载于"http://www.cnblogs.com/KissKnife/数据库

理论性的东西,每每容易把人人都看得懂的东西写成连鬼都看不懂,近似于主任医生开的药方。从前学范式的时候,把书中得概念翻来覆去看,看得痛心疾首深恶痛绝,再加上老师深切误导,最后一塌糊涂。借助网络资源,本身写了一篇,本身是看懂了,但愿对你们也有所帮助,有错误帮忙指正。网络

数据库范式(Normal forms):是用于规范关系型数据库设计,以减小谬误发生的一种准则。app

1NF(first normal form) dom

Table faithfully represents a relation and has no repeating groups.数据库设计

数据库表必须如实地展示“关系”,而且不容许有“重复组”出现。函数

这样的概念真是使人痛心疾首,咱们只好再搬出1NF的的做者之一Chris Date的解释:性能

1. There's no top-to-bottom ordering to the rows.学习

(任意两行没有特定的顺序关系。不存在一个特定的理由要某一行必须在另外一行以前。)spa

2. There's no left-to-right ordering to the columns.设计

(任意两列没有特定的顺序关系。)

3. There are no duplicate rows.

(不容许存在重复的行。若是一张表没有Unique Key,事实上它是违反1NF。)

4. Every row-and-column intersection contains exactly one value from the applicable domain (and nothing else).

(不容许出现空值Null,这一点不一样做者是有争议的。事实上咱们经常违背这点。)

5. All columns are regular [i.e. rows have no hidden components such as row IDs, object IDs, or hidden timestamps].

(不容许存在隐藏字段。不知道Oracle的Rowid属不属于这个?)

有人从第四点的“one value”大肆挖掘,因而咱们就见到了书上这样的定义:“若是一个关系模式R的全部属性都是原子的,即不可再分的基本数据项,则RÎ1NF”。

这一点被认为是1NF的核心,“关系模式R”↔“表”,“属性” ↔ “列”,下面是一种与1NF不一致的状况,一般这是一类很明显的设计缺陷:

ID

Artist

FavoriteColor

…… 

1

Babyface

Blue,Yellow

……

2

Sting

Green

……

对上例咱们不能把它拆分红FavoriteColor一、FavoriteColor2……由于首先咱们不能肯定该拆分红几列;其次FavoriteColor1与FavoriteColor2在结构、含意方面都是相同的,这实际上也是一类“repeating group”;同时这种设计会致使某些查询困难,好比“有哪些艺人喜欢黄色?”

解决方案是将表拆分红两个:

ID

Artist

…… 

1

Babyface

……

2

Sting

……

ID

FavoriteColor

1

Blue

1

Yellow

2

Green

总结: 

1NF最核心的 “原子性”,违反此规范的可能性:接近于0%。不过,网上不少帖子说在关系型数据库中根本不可能违背1NF,我认为这是不对的。 

2NF(second normal form):

No non-prime attribute in the table is functionally dependent on a part (proper subset) of a candidate key.

不存在非主属性对任一候选键的部分函数依赖。

若是解释完下面几个概念,这个定义就能够读懂了:

Superkey:超级键(L),若是属性或属性组合能惟一标识一条记录,则它是一个Superkey。

Candidate key:候选键,当Superkey只包含一个属性时,则它是一个候选键;当Superkey包含一组属性时,仅当这一组属性不包含另外一Superkey时,它是一个候选键。换句话说,候选键是“纯净的”、最小化的Superkey。

Non-prime attribute:非主属性,未在任何候选键中出现的属性,即为非主属性。

举例来讲,对表{First_name,Last_name,Address},假定全名不重复,则:

Superkey:

{First_name,Last_name}

{First_name,Last_name,Address}

Candidate key:

{First_name,Last_name}

Non-prime attribute:

Address

浅白版:“2NF针对的是复合候选键(即键包含的字段个数>1)的状况,非主属性不能只依赖于复合候选键中的一部分字段。”显然,若是是非复合候选键,若是它符合1NF,那么它必定符合2NF。

假设有这样一张涉及艺人与唱片公司的关系表:

Artist

艺人 

Company

唱片公司 

DurationYears

签约总年数 

CompAddr

公司住址 

Babyface

Solar

4

Indiana

Babyface

Laface

2

Indiana

       

显然,{Artist,Company}为能够做为一个候选键,DurationYears在这没有问题,但CompAddr是违反2NF的,它只依赖于候选键的一部分(依赖于Company),这是违反2NF的,为了消除这种状况,咱们能够:

Artist

艺人 

CompID

唱片公司 

DurationYears

签约总年数 

Babyface

1

4

Babyface

2

2

ID

Company

唱片公司 

CompAddr

公司住址 

1

Solar

Indiana

2

Laface

Indiana

总结: 

对于2NF,若是关系中的候选键只包含一个属性,能够直接略过。 

 

在考虑2NF的过程当中,不要把几个无关的实体的属性杂揉放在一个关系中,好比Artist是一个实体、Company是一个实体,它们能够有一系列的关联表(也是实体),但在关联表中尽可能不要引入前两个实体的无关属性。 

3NF(Third normal form)

Every non-prime attribute is non-transitively dependent on every key of the table.

不存在非主属性对任一键(候选键)的传递依赖。

传递依赖,你能够顾名思义,这里就再也不引入定义了,举个例子,有下面一张表:

Tournament

赛事 

Year

年份 

Winner

冠军 

Winner Date of Birth

冠军生日 

Indiana Invitational

1998

Al Fredrickson

21 July 1975

Cleveland Open

1999

Bob Albertson

28 September 1968

Des Moines Masters

1999

Al Fredrickson

21 July 1975

Indiana Invitational

1999

Chip Masterson

14 March 1977

这里的候选键为{Tournament,Year},显然有这样的决定关系:

{Tournament,Year}→Winner

{Tournament,Year}→Winner→Winner Date of Birth

其中第二条就属于违反3NF的状况,由于Winner Date of Birth依赖于Winner而不是直接依赖于候选键。这种状况下,能够将Winner,Winner Date of Birth单独做为一张表,这里不赘述。

总结: 

我以为大多数人凭借直观感受,就可以使设计的关系符合3NF,因此这些理论,你只须要姑且读之。 

BCNF(Boyce-Codd normal form)BoyceCodd是该范式的两名做者。) 

Every non-trivial functional dependency in the table is a dependency on a superkey.

表中的任何非平凡函数依赖,都必须是对superkey的依赖。

non-trivial functional dependency:非平凡函数依赖,若是存在一个决定关系x→y,且y并不是x的子集,则叫着y非平凡函数依赖于x。

BCNF与3NF的最大区别是它并不只针对非主属性(non-prime attribute)来讲,它发生的时候经常是表中根本不存在非主属性,以致于它不可能违反2NF或3NF。而BCNF的出现就是为了扩大“打击面”。

因而BCNF的主旨是:补充对发生在主属性(prime attribute)身上的函数依赖的约束,由于对于非主属性的约束已经在3NF中完成了。

例子,使用关系表描述学生、课程、教师的关系(假定一名教师只负责一门课程,一门课程则能够由多位教师负责):

Student

学生 

Course

课程 

Teacher

教师 

S1

C1

T1

S1

C2

T2

S2

C1

T1

S2

C2

T3

S2

C3

T2

候选键:

{Student,Course}

{Student,Teacher}

所以这里不存在非主属性,而在主属性的函数依赖中,存在Teacher→Course,这属于违反BCNF的状况。

但是,问题是这个表看起来还挺正常的啊?!它的毛病在于,咱们没法阻止相似最后一行这样的数据插入,而这会致使与前提“一名教师只负责一门课程”违背。因此咱们仍是须要将它拆分:

Student

学生 

Teacher

教师 

S1

T1

S1

T2

S2

T1

S2

T3

Teacher

教师 

Course

课程 

T1

C1

T2

C2

T3

C2

这样,在“Teacher-Course”表中,借助主键的帮助,最后能够避免违背“一名教师只负责一门课程”这个前提。

那么,若是没有这样一个前提,是初的设计是否符合BCNF?目前看来是的。

真实的状况可能更为复杂,下面这个更接近于个人一些经历:

1)学生须要学习多门课程

2)一门课程可能有多位教师负责

3)一位教师可能负责多门课程

4)某一班级的某一课程对应的教师是固定的(一位)

据此,为了描述学生、课程、教师三者的关系,从这一团乱麻中最先跳出来的大概是这样的表:

Student

学生 

Class

班级 

Course

课程 

Teacher

教师 

       
       

候选键:

{Student,Course}

咱们能够明显地看到Student→Class违反了2NF,因而:

Student

学生 

Class

班级 

   
   

Class

班级 

Course

课程 

Teacher

教师 

     
     

从这两张表,仔细考虑,即使咱们经过Class关联两张表,仍是没法得出学生与课程的关系(只能得出可供该学生选择的课程),因此咱们须要再添加一张表:

Student

学生 

Course

课程 

   
   

最后大概是这么三张表,可能还有其它的方案,这里只是举例说明,就不纠缠了。

在BCNF以后,还有4NF,5NF,DKNF,6NF,等何时有空了再看看是什么东东。

"

再转一篇百度文库里的文章, 没有上篇那么通俗易懂可是内容很全

"

范式 

就关系数据库而言,一向认为:从其余元素中消除数据冗余问题,去除重复每每以减小冗余, 从特定的表中最小化冗余意味着摆脱没必要要的数据。

商业上来说,主要目标是一般保存空间和组织的数据可用性和可管理性,而不牺牲性能。此外,要求强烈繁忙的应用程序和最终用户的须要每每须要以多种方式打破规则的范式,以知足性能要求。第三范式之外的范式经常被忽视和有时甚至是第三范式自己就是多余的。

范式是一个升级的过程,每一个上层的模式都是创建在下一级范式之上的。

消除数据冗余的影响以下:

 ❑物理空间须要存储的数据减小。

 ❑数据变得更有组织。

 ❑范式化容许修改少许的数据(即单记录)。换言之,一个表的具体字段记录更新时,会影响其余引用他的表。

首先咱们对一些概念性的东西来进行一个总结,经过对这些概念的理解,历来从根本上作到合理的数据库设计:

 

异常

    添加异常:当咱们添加一条记录的时候,他依赖的主表记录尚未记录,而该记录已经插入成功。

    删除异常:当咱们的主表记录删除,而依赖他的子表没有清空对应的记录。

    更新异常:当咱们的主表记录有更新草组,而已来他的子表没有相应的更新记录。依赖,决定因子

 

    函数依赖:当Y的值由X决定的时候,咱们就说Y函数依赖于X,这就相似于一个线性方程:Y=X+1;相似的ERD图中,咱们这样表示 ,很清楚的看到表Category,中的主键是CategoryID,他决定着其余字段的值Name和Pic,咱们就说Name或者Pic 函数依赖于CategoryID,他们之间就是一个函数依赖关系。

    决定因素:如上例中,CategoryID就是一个决定因素,他决定其余字段的值,Y=X+1中,X就决定着Y的值,虽然加了一个常量。

    传递依赖:当X决定Y,Y决定Z的时候,咱们就说Z传递依赖于X,,从这个ERD图中,咱们看到Account账号表中的City字段,他被AccountID所决定,而City字段的值又决定了College的值,由于大学确定是被城市所决定,因此College就传递依赖于AccountID。

    候选键:候选键(潜在的或容许的主键)能够扮演主键的角色他能够是一个表中的一个字段或组合字段——也就是一条记录中的惟一标识。,咱们看到这个表,Customer表(客户表),字段分别表示,客户ID,客户名,货币缩写码,货币,转换汇率,地址。这个表咱们没有定义主键,可是咱们能够推测那些能够成为主键,那么那些键就叫作候选键。,咱们就看到了,全部能成为主键的可能,表中的#就是主键的标识符。

    彻底函数依赖:当X决定Y,可是X不被X和Z的组合所决定,换句话说,YE依赖于独立的X,若是Y依赖于X加上一些其余的东西,那就不是彻底函数依赖,本质上,决定因素X不能是一个组合键。,咱们来看到旅游表Travel,Country是旅游的国家,Populication是旅游的城市,同时TravelID和CountryID是主键,能够看出来只有CountryID决定着Populcation人口,可是这里有两个主键,因此Populication并无彻底函数依赖于主键组合,只部分依赖于CountryID

    多值依赖:某个字段中的值之一个集合,或者是用某种分隔符分割开来的元素集合,咱们就称为多值依赖。很经典的,Path保存的这个递归表的全部上司的级别,好比老大的ID是1,老2是2,Path 就保存1,2,像这样的字段,咱们就称为多值依赖。

    循环依赖:循环依赖就如其名,是一个个闭环的依赖系统。A依赖于B,B依赖于C,C依赖于A。范式(学术定义)

 

    第一范式(1NF):消除表中全部重复的记录,除了主键之外的全部其余字段所有依赖于主键。

    第二范式(2NF):全部非键值字段必须所有彻底函数依赖于主键,当一个字段彻底函数依赖于一组组合主键的部分函数依赖是不容许的。

    第三范式(3NF):消除传递依赖,意味着一个字段必须非间接的依赖于主键  正规化范式(BCDF):全部表中的决定因素必须是一个候选键,若是只有一个候选键,那么就和第三范式是同样的。

    第四范式(4NF):消除多值依赖。

    第五范式(5NF):消除循环依赖。

 

咱们从一个比较容易的位置来理解范式,经过上述的理解,加上实际的操做范式,让咱们对数据库的设计有一个比较深的认识,以决定什么状况下用范式。

    第一范式(1NF):经过建立一个新表来移除重复的元素,使他们成为一个主从关系或者是one to many的关系,相似下图:。

    第二范式(2NF):创建在1NF的基础上,就是移除重复的值到一个新表中去,新表有惟一的主键,而主表有一个对新表的外键的引用,排除存在的部分依赖。以下图:Bookid 是book表的主键,而author是author1的主键,在book表中创建author,主表有一个对子表的外键引用,而不是把author也定义为主键,那样就存在部分函数依赖,由于bookid就已经肯定了title,page,isbn等等信息。

    第三范式:消除传递依赖,以下图:咱们把多对多的关系变化成上图的关系。这是一种简单的形式,下面展现一个另一种状况:这里的表分别是客户(客户名,货币号,货币,货币,汇率,地址),提供商(客户名,货币号,货币,汇率,地址)。首先他们的地址决定了他们的货币状况,而地址又是由客户或者提供商决定的,因此他们之间存在一个传递依赖关系,并且最好是把相同的存在于不一样的数据移植到一个新表中去。前面咱们提到了这个关系,也是一个不知足第三范式的表,City和College以及主键存在传递关系,因此能够把College移植到一个新表中去,还有一些存在订单的表中,有相似(qty(数量),price(单价),total(总价))的结构,qty和price决定了total,而订单号决定了qty和,price,因此也存在一中依赖关系,咱们要删除total字段,可是不是都遵循范式的表都是好的结构,咱们仍是要根据实际状况,好比在一个数据仓库的设计中,汇总字段就是必须的。

    超三范式(Beyond 3NF)中的one to one关系,这个主要用户当咱们表中一些字段常常存在空值的时候,咱们将存在的NULL字段移到一个新表中去,而后创建1对1的关系。

    BCNF范式:BCNF划分红多个表的表格,以确保没有一个单一的表有更多不止一个潜在的主键。这是个人理解BCNF 。在我看来,是BCNF 用于商业环境是“过分设计“的。从本质上讲,从数学的角度上它的漂亮,但在商业环境中它不是很酷。下面的例子是一个BCNF转换:

    第四范式:消除多值依赖,很经典的一个环境就是,咱们的递归表问题,一个Manager有多个Employee,而后每条记录都有一个Path老表示这种关系,因此path和EmployeeId就存在一个多对多的关系。咱们就应该从新创建一个新表,用来消除Path字段,新表中就保留一个EmployeeId做为外键,另一个EmployeeId用来表示他的下属。

    第五范式:消除循环依赖,以下图:在这个实例中Solution表中的键都是主键,他们存在这样的关系,每两个组合的主键决定另一个主键。比方项目1和经理1就决定了有哪些下属属于项目1和经理1关系,而一个经理1和他的下属员工又决定了他们参与了那些项目。因此他们之间实际上是一个循环的依赖。

     反范式:这种类型的应用在商业正常化环境将致使业绩不佳,更精确的数学的必要性比商业要低的多。所以: 

    一样的,对于第4范式,咱们不少时候都没有必要去消除他们里面多值的依赖,那样对性能来讲简直是个噩梦。因此不少状况下,咱们都是用相似的处理CSDN上的,显示本身的技术就是这样的反范式化转换。

    在商业环境中,绝大多数超越第3范式的设计都是不切实际的。由于应用程序在3NF级别就能变现的至关出色。咱们上述的不少例子,将指向箭头反过来就是先了反范式化。因此咱们要对总体的结构有个比较深的认识,才肯定咱们是否范式话或者反范式化,范式化越深的东西越致使表的增多,也就意味着查询的join开销。

 

    总结一下反范式化的一些准则:

      分离活动和静态的数据,数据可分为独立的物理表,即

    活动和静态表。那些累计的历史数据致使咱们占据了绝大多数的空间。这是影响性能的最常常的数据,在数据仓库设计中,咱们常常将无效的静态的数据移植到数据仓库中,因为OLAP和数据挖掘。

      在表之间复制字段,在那些不是直接有连接表的之间复制字段,使得咱们没必要每次进行查询都要经过第3方表,越少的join操做,使得性能的大幅度提高。

      在夫表中创建统计字段,这样能够减去消耗大的聚合操做,可是实时更新会给咱们带来另外的麻烦。

      分离繁重和轻松的字段,就像把活动和静态的数据数据表分离同样,这个避免持续物理扫描不多使用的数据字段,尤为是当这些字段不包含空值。这是一个潜在的合理利用4NF在分离表格分为两个表格,相关的一对一关系。

"

上面的文章是有图的, 因为图太多了就没贴, 能够在这里下载有图完整版

最后附上本身记的老师的理解:

2NF:  每一个非主属性彻底函数依赖于码。(没有非主属性属于2NF)

3NF:  每一个非主属性既不部分依赖于码,也不传递依赖于码。

BCNF:每一个非主属性和主属性既不部分依赖于码,也不传递依赖于码。(完全解决删除异常问题)

最后的最后附一张很是简单明了的图:

网上的关于多值依赖的解释:

"

什么是多值依赖?书上的概念是:设R(U)是属性集U上的一个关系模式。X,Y,Z是U的子集,而且Z=U-X-Y.关系模式R(U)中多值依赖X→→Y成立,当且仅当对R(U)的任一关系r,给定的一对(x,z)值,有一组Y的值,这组值仅仅决定于x,与z无关!太抽象了!看不懂!

答:举个例子
U{w,s,c} w是主码
x{w}
y{s}
z{c}  能够看到它们知足X,Y,Z是U的子集,而且Z=U-X-Y.
{w,c}->{s},同时s的值和c无关,由于{w,c}->{s},实际上是由{w}->{s}获得的。
因此这里就有W->->S
同理可得出W->->C 

"

相关文章
相关标签/搜索