第一范式(1NF)
属性的不可再分特性:称为关系的第一范式。
举刚才的例子:
一个家庭中有丈夫,妻子,子女,这些属性对于这个表来说都是不可再分的了。
概念:也就是说要求属性具有原子性~ 不可再分解!
数据库表中的每一列都是不可分割的基本数据项,同一个列中不能有多个值。
如果重复
如果出现重复的属性,就可能需要定义一个新的实体,新的实体由重复的属性构成,新实体与原实体之间为一对多的关系。在1NF中表的每一行只包含一个实例的信息。无重复列~
对于任何一个数据库,1NF是对关系模式的基本要求,不满足1NF的数据库就不是关系数据库。当前的任何DBMS中,不可能做出不符合1NF的数据库,因为这些DBMS不允许你把数据库的表的一列再分成多个列。
第二范式(2NF)
第二范式是在第一范式的基础上建立起来的,即满足第二范式必须先满足第一范式1NF。 第二范式2NF要求数据库表中的每个实例或行必须可以被唯一区分。
一般来说,之前是依靠每个行可能有一个或某几个数据不同来区分。
这里一般就是加上id,或者所谓的uuid来区分,这也就是主键/主码~
2NF要求实体的属性完全依赖主关键字。 所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,要求记录有唯一标识。
所谓完全依赖是指不能存在仅依赖主关键字一部分的属性,如果存在,那么这个属性和主关键字的这一部分应该分离出来形成一个新的实体,新实体与原实体之间是一对多的关系。为实现区分通常需要为表加上一个列,以存储各个实例的唯一标识。简而言之,第二范式就是属性完全依赖于主键。
举例:
CREATE TABLE `articles` (
`id` int(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`article_uuid` char(32) NOT NULL DEFAULT '0' COMMENT '文章uuid',
`title` varchar(200) NOT NULL DEFAULT '0' COMMENT '文章名',
`user_uuid` char(32) NOT NULL DEFAULT '0' COMMENT '楼主uuid',
`create_time` char(19) NOT NULL DEFAULT '2000-01-01 00:00:00' COMMENT '帖子创建时间',
`last_update_time` char(19) DEFAULT NULL COMMENT '最后跟新时间',
`img` varchar(200) DEFAULT '0' COMMENT '图片',
`texts` text COMMENT '正文',
PRIMARY KEY (`id`)
)
创建了一个表,但是有若干个uuid 和一个id,其实这些都是可以称为候选键/候选码,其实也可以看成是一个联合主键,也就是说主键其实有几个属性。但是我们可以发现,其实title只取决于article_uuid,而texts和img等只取决于id,那其实就可以拆分成两张表了:
CREATE TABLE1 `articles` (
`article_uuid` char(32) NOT NULL DEFAULT '0' COMMENT '文章uuid',
`title` varchar(200) NOT NULL DEFAULT '0' COMMENT '文章名',
`create_time` char(19) NOT NULL DEFAULT '2000-01-01 00:00:00' COMMENT '帖子创建时间',
`last_update_time` char(19) DEFAULT NULL COMMENT '最后跟新时间',
)
CREATE TABLE `articlesX` (
`id` int(20) NOT NULL AUTO_INCREMENT COMMENT 'id',
`user_uuid` char(32) NOT NULL DEFAULT '0' COMMENT '楼主uuid',
`create_time` char(19) NOT NULL DEFAULT '2000-01-01 00:00:00' COMMENT '帖子创建时间',
`last_update_time` char(19) DEFAULT NULL COMMENT '最后跟新时间',
`img` varchar(200) DEFAULT '0' COMMENT '图片',
`texts` text COMMENT '正文',
PRIMARY KEY (`id`)
)
这就是符合第二范式了。属性不是依赖主键的一部分,实体的属性完全依赖主键,不能依赖它的一部分!
第三范式(3NF)
满足第三范式3NF的也是必须先满足第二范式2NF,第三范式要求一个数据库表中不包含已在其他表中已包含的非主关键字信息。
也就是字段冗余性的约束,任何字段不能由其他字段派生,
举例:
CREATE TABLE `bl_photo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`photoName` varchar(200) DEFAULT NULL,
`photoPath` varchar(200) DEFAULT NULL,
`shrinkPhotoPath` varchar(200) DEFAULT NULL,
`photoSize` bigint(30) DEFAULT NULL,
`uploadTime` datetime DEFAULT NULL,
`downloadCounts` int(20) DEFAULT '0',
`photoId` varchar(255) DEFAULT NULL,
`uploadUserId` int(10) NOT NULL DEFAULT '0',
`adaptType` int(11) NOT NULL DEFAULT '4',
`checkStatus` int(10) NOT NULL DEFAULT '0',
`photoData` varchar(255) DEFAULT NULL,
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
这里这个主键是id,这个属性可以唯一确定其他所有属性,知道了id就能知道图片的名字,路径,上传时间等。
但是这里还有个photo_id,它不是主键,但是我们又发现photoData 和 uploadUserId取决于这个候选码,也就是说photoData依赖photo_id,photo_id依赖id。
这就存在了传递依赖。 数据冗余~
解决:
拆分成两个表:
CREATE TABLE `bl_photo` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`photoName` varchar(200) DEFAULT NULL,
`photoPath` varchar(200) DEFAULT NULL,
`shrinkPhotoPath` varchar(200) DEFAULT NULL,
`photoSize` bigint(30) DEFAULT NULL,
`uploadTime` datetime DEFAULT NULL,
`downloadCounts` int(20) DEFAULT '0',
`photoId` varchar(255) DEFAULT NULL,
`adaptType` int(11) NOT NULL DEFAULT '4',
`checkStatus` int(10) NOT NULL DEFAULT '0',
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
CREATE TABLE `XPhoto` (
`photoId` varchar(255) DEFAULT NULL,
`uploadUserId` int(10) NOT NULL DEFAULT '0',
`photoData` varchar(255) DEFAULT NULL,
) ENGINE=InnoDB AUTO_INCREMENT=101 DEFAULT CHARSET=utf8;
我们在原来的表中删除了依赖photo_id的属性,然后新建一个表,这样如果要搜索依赖它的属性,就利用数据库连接来实现:
select p.id,p.photo_data,d.photo_data from bl_photo p,XPhoto d where p.photo_id=d.photo_id
缺点:
- 数据库连接会带来一部分的性能损失
- 并不是数据库范式越高越高
- 有时会在数据冗余与范式之间做出权衡,在实际的数据库开发过程中,往往会允许一部分的数据冗余来减少数据库连接。
区分2NF和3NF
2NF:非主键列是否完全依赖于主键,还是依赖于主键的一部分,一般情况下如果主键是一个字段那么是满足的,主键是联合主键就要考虑了;(是否依赖主键的一部分)
3NF:非主键列是直接依赖于主键,还是直接依赖于非主键列。(是否直接依赖~!或者说多个依赖并存)