关系:一个关系对应通常所说的一张表。 元组:表中的一行即为一个元组。 属性:表中的一列即为一个属性;每一个属性都有一个名称,称为属性名。 候选码:表中的某个属性组,它可以唯一确定一个元组。 主码:一个关系有多个候选码,选定其中一个为主码。 域:属性的取值范围。分量:元组中的一个属性值。
数据库表中的所有字段都是单一属性,不可再分的。其实这句话好理解,意思就是说表中的每个字段都是对应一个特定的单一属性,比如年龄和名字,而如果有一个字段存放了一个JSON字符串,里面包含了各种字段,那这个字段就不是对应一个特定的单一属性,也就是违反了第一范式。
create table user
(
user_id int auto_increment,
username varchar(24) null,
age int null
);
数据库的表中不存在非关键字段对任一候选关键字段的部分函数依赖,部分函数依赖是指存在着组合关键字中的某一关键字决定非关键字的情况。
第二范式是在满足第一范式的基础上更进一步,而这个定义看上去非常生涩,其实含义就是说数据库中的每条数据都会有一个唯一标识,查询这个唯一标识就可以找到数据,这个主键有可能是一个字段,也有可能是多个字段组成的,第二范式的要求不允许的是,在多个字段组成唯一标识的情况下,其他的字段只和唯一标识中一部分字段有关联,而不是唯一标识中的所有字段。
比如下列的order_info表,唯一标识应该是依靠order_number和goods_name来查询订单中某一种商品,但是goods_price这样的字段之和goods_name有关联,所以它违反了第二范式。
create table order_info
(
order_number varchar(24) null,
order_price int ,
goods_name varchar(24) null,
goods_ quantity int,
goods_price int
);
所以按照第二范式的标准,应该拆分成两张表,这样每个表存储的数据更清晰,每条数据也保证了唯一性。
create table order_info
(
order_id int auto_increment,
order_number varchar(24) null,
order_price int,
quantity int
);
create table goods
(
goods_id int auto_increment,
goods_name varchar(24) null,
goods_price int
);
数据表中不存在非关键字段对任意候选关键字段的传递函数依赖。
第三范式则是在第二范式的基础上进行扩展,定义看上去也很生涩,它的意思是说一个表中的非关键字段和关键字段有关联,而又有其他的非关键字段和这个非关键字段有关联,这个关联关系是传递关联的,关键字段其实就是上面说的能够组成唯一标识的字段。
比如下面的goods表,goods_brand和goods_id有关联,而goods_brand_des则和goods_brand有关联。
create table goods
(
goods_id int auto_increment,
goods_name varchar(24) null,
goods_price int,
goods_brand int,
goods_brand_des int
);
解决方法就是拆分成两张表,去除这种传递依赖。
create table goods
(
goods_id int auto_increment,
goods_name varchar(24) null,
goods_price int,
goods_brand int
);
create table goods_brand
(
goods_brand_id int auto_increment,
goods_brand varchar(24) null,
goods_brand_des int
);
所有的范式其实都是为了解决数据库操作异常,就是下列三种。
-
插入异常
如果某实体随着另一个实体的存在而存在,即缺少某个实体时无法表示这个实体,那么这个表就存在插入异常。
实体其实就是对应的数据概念,比如用户,订单等。例如第二范式中的例子,如果不拆分,当一个商品没有订单数据时,商品价格之类的数据也都没有,也就是缺少了商品实体,这就是插入异常。
-
更新异常
如果更改表所对应的某个实体实例的单独属性时,需要将多行更新,那么就说这个表存在更新异常。
在第三范式中的例子,如果不拆分表,当goods_brand字段更新时,goods_brand_desc也需要更新,因为它们之间有关联关系,拆分之后就不会。
-
删除异常
如果删除表的某一行来反映某实体实例失效时导致另一个不同实体实例信息丢失,那么这个表中就存在删除异常。
和更新异常一样是对应第三范式中的例子。
实际上数据库范式是来自数据库规范化概念(Database normalization),关系模型的发明者埃德加·科德最早提出这一概念,并于1970年代初定义了第一范式、第二范式和第三范式的概念,还与Raymond F. Boyce于1974年共同定义了第三范式的改进范式——BC范式。
所以可以说是早期的一种非常理论化的学术派的东西,用作数据库的设计,本质上其实也可以看到数据库范式的就是把表划分的越来越细,职责越来越清晰,但是坏处是查询的数据如果是多个维度的,那么需要写很复杂的联结查询,通常只会应用到第三范式。而反范式的说法,也就是合理的打破范式的规定,制定一些合理的冗余,虽然会造成一些操作异常和更新异常,但是查询起来的复杂度也会大大降低,其实就是在业务维度上来对设计的一种权衡。
https://zh.wikipedia.org/wiki/%E6%95%B0%E6%8D%AE%E5%BA%93%E8%A7%84%E8%8C%83%E5%8C%96