维基百科的定义以下:html
数据库规范化,又称数据库或资料库的正规化、标准化,是数据库设计中的一系列原理和技术,以减小数据库中数据冗余,增进数据的一致性。web
数据库范式是埃德加·科德设计出来的。在1970年代初,他定义了第一范式(First normal form)、第二范式(Second normal form),和**第三范式(Third normal form)**的概念。数据库范式能够理解成一系列的规范或者规则,为了实现数据库规范化的目标,咱们须要按照这些范式的规则来优化数据库。数据库
关于这些范式的规则我会在文章后续部分说明。dom
如今数据库设计最多知足第三范式,广泛认为范式太高,虽然具备对数据关系更好的约束性,但也致使数据关系表增长而令数据库IO更易繁忙,原来交由数据库处理的关系约束现更多在数据库使用程序中完成。数据库设计
所以,本文数据库的优化实例只作到第三范式。svg
为了更准确,简洁地定义各个范式的规则,咱们须要知道一些术语的含义。对于有些术语来讲,我不打算写出它标准化的定义,这是由于标准化定义十分晦涩。对于这样的术语,俺直接给出相应的例子,理解它表明的是什么东西就行。优化
下面俺给出一个关于上面部分术语的例子。这个例子来源于 yangyang17atom
假若有如下学生和教师两个表:翻译
Student
(student_no, student_name, student_age, student_sex, student_credit, teacher_no)设计
Teacher
(teacher_no, teacher_name, teacher_salary)
超键:Student表中可根据学生编号(student_no),或身份证号(student_credit),或(学生编号,姓名)(student_no,student_name),或(学生编号,身份证号)(student_no,student_credit)等来惟一肯定是哪个学生,所以这些组合均可以做为此表的超键
候选键:候选键属于超键,且是最小的超键,即若是去掉超键组合中任意一个属性就再也不是超键了。Student表中候选键为学生编号(student_no),身份证号(student_credit)
主键:主键是候选键中的一个,可人为决定,一般会选择编号来做为表的主键。
在这个小节,俺会用具体的例子来讲明每一个范式所包含的规则。
第一范式的定义:
First normal form (1NF) is a property of a relation in a relational database. A relation is in first normal form if and only if the domain of each attribute contains only atomic (indivisible) values, and the value of each attribute contains only a single value from that domain.
第一范式必须符合下面3个标准:
下表是一个不符合第一范式的 例子,Telephone Number
列并非原子的,它能够继续拆分下去。
解决上面问题的一个直观方法是多引入一列,以下图所示。可是,这种方法仍然有3个问题。第1、下表仍然包含 “repeating group”,即包含概念上类似的属性,电话号。第2、这样作会引入没有意义的顺序。好比,为何 555-861-2025 放到 Telephone Number1 列,而不是放到 Telephone Number2 列呢?第3、当一个客户再多一个号码时,会修改表结构,增长一列。
下面的表结构能够解决上面的问题。因为第一范式要求能惟一地标识出一个元组,而如今 Customer ID 重复了,因此咱们须要 Telephone Number 与 Customer ID 的组合才能标识出一个元组。
另外一种设计方案以下所示,它是使用两张表。
第二范式必须知足下面2个条件:
第2个条件翻译过来的含义为:任何一个非主属性不能依赖于候选键属性集合的真子集属性。
下表的每一个值都是单一值,因此它符合第一正规化。但它不符合第二范式。这是由于,一个元件 ID 和供应商 ID 合在一块儿组成一个主键,但供应商的名称和住址却只和供应商 ID 有关(部分依赖)。
把上表的结构改为下面的结构,就符合第二范式了。
第三范式必须知足下面2个条件:
也就是说,符合第三范式的表结构不该该包含 transitive dependency. 即,非主属性之间不能有依赖关系。好比下表的结构就包含 transitive dependency,由于非主属性 Author 决定了另外一个非主属性 Author Nationality.
在这个小节中,俺会给出一个数据库表的初始结构,它不符合数据库范式。我会一步一步地改进它,直到让它知足数据库的第三范式。下表是一个不符合范式的初始结构:
初始表中的 Subject 列并非原子的,一种方式是将其拆分红3个列。以下所示:
若是用上面的方式,当某本书增长一个 subject 时,就须要更改表结构,增长一列。所以,用下面的方式修改表,使其符合第一范式会更好一些。
拆分红上面的结构之后,咱们须要把 Subject 表与 Book 表链接起来。因为一本书可能对应多个 subject,而一个 subject 也可能对就多本书,这是一个典型的 多对多 关系。所以咱们须要新建一张关联表:
从下表能够看出,{Book} 和 {Book Type} 是一个候选键。可是,只有一个 price 属性是由这2个主属性共同影响的(这是合理的,由于一样一本书,电子版与精装的价格确定是不一样的)。其它的属性都是只由 Book 这个主属性影响的。所以,这不符合第二范式。
按照下面的方式修改之后,就符合第二范式了。
因为下表中的非主属性 Genre ID 决定了另外一个非主属性 Genre Name,即存在 transitive dependency,因此它并不符合第三范式。
改为下面的结构之后,就符合第三范式了。至此,咱们从一个不符合任何范式的初始表结构,一步一步地改为了如今这个结构。