关系型数据库与范式
一、什么是关系?
关系是一组属性的关联。
表现为一张表,表头是属性名,每一行是一个关联的元组,其中每一列是不同的属性值。
关系既可以表示实体Entity,如下关系: 课程表, 每一行就是一个课程。
关系也可以用来表示实体之间的关联(relationship)。
如下表就是学生选课关系,每一行表示一个学生的选课记录。
二、实体-联系模型
E-R图
实体集: 对应现实中的实体,以矩形表示
属性: 描述对象某方面特性的数值。 以椭圆形表示
联系: 对应实体之间的关联, 联系也可能有属性
下图:学生选课的ER图
联系的三种类型, 1对多, 多对1 ,多对多。
1对多与多对1本质是一种,由箭头指向1的一方。
多对多则没有箭头。
三、设计原则
1.真实性
关系模型应反应真实世界情况。
如给学生增加一个 Price属性,在选课场景就不符合现实。
再如学生与课程之间,学生能选多个课,课也能有多个学生选,它就是个多对多关系,设计成为1对多 就是不合事实的。
2.避免冗余
任何事物或属性只表达一次。
如课代表的代表年龄属性。学生表已经有了课代表的年龄,没必要单独拿出来。
3.简单性
避免引入过多的元素,设计尽量简单明了。
4.合理选择元素类型
元素究竟作为属性还是作为实体。
如电影资料库中:电影公司总裁适合作为属性还是实体?
以及:制片公司是不是适合作为属性呢?
一般而言,如果一个事物具有比名称更多的有用信息,适合作为实体。
四、函数依赖
一个学号只能对应一个学生。
一个学生只能有一个系。
因此『学号』确定后,Sname 与 Sdept就都确定了,这种关系类似于数学上的函数(y=f(x),对于任意的x,y的值都是唯一确定)或者说Sname Sdept函数依赖于Sno。
五、关系的Key
如果一组属性{A1,A2,A3….An}满足如下条件,则称他们为关系的Key。
这些属性函数决定关系的所有其他属性。
这些属性的任何一个真子集都不能函数决定R的所有其他属性。
{Sno ,Cname} 构成 如下关系的key。
六、完全依赖与部分依赖
对于函数依赖 W-> A, 如果存在 V是W的真子集, 且 V->A, 则称A部分依赖于W,若不存在这样的V, 则A 完全依赖于W。
容易看到, {Grade} 完全依赖于 {Sno,Cname}。
而 {Sdept, Mname} 部分依赖于 {Sno,Cname} 。
七、传递依赖
如果X->Y (Y依赖于X),且 X不依赖于Y,而 Z 依赖于Y,则称 Z传递依赖于X。
易知: Mname传递依赖于 Sno , 因为 Sno -> Sdept, Sdept不能决定Sno, 而Sdept -> Sno。
八、第一范式
第一范式(1NF):字段具有原子性,不可再分。
什么情况下会违反第一范式?
把学生的名字绰号年龄 连在一起放在一个学生字段就违反了第一范式。
一般由于关系数据库的属性都是简单属性,不会违反第一范式。
Nosql数据库因为其中存放的是文档,通常不满足第一范式。
九、第二范式
第二范式(2NF):满足第一范式,而且所有的非主属性都完全函数依赖于Key。
违反第二范式的例子:
这个里面Mname 只是部分依赖于Sno ,而不是完全依赖于 Sno 与 Cname, 这样的设计就会出现问题。
a.数据冗余,假设同一个系40个学生,Mname 系主任名字重复40次 。
b.更新异常,若调整了系主任,相应的元组 Mname值都要更新,有可能会出现同一个系的学生 系主任不同。
c.插入异常,新的系还没有学生没有选修记录时,没有学号关键字,只能等有人选修才能把Mname存入。
d.删除异常,若学生已经结业,从当前数据库删除选修记录。可能系主任的信息就丢失了。
出现部分依赖时, 应该做关系的拆解。
将 Sno Sname Sdept Mname 拆出为 一个表。
Sno Cname Grade 拆为另一个表。
学生表
课程表
十、第三范式
若关系方式R属于第2范式, 且每一个非主属性都不传递依赖于主键, 则R属于第三范式。
刚才拆解完的表中 Mname对Sno 仍然有传递依赖。
如下Mname 对 Sno有传递依赖, 应该进一步分解为两个独立表。
十一、模式分解的原则
无损连接(数据等价)
分解后的表通过自然连接, 能够无损的还原分解前的表。
保持依赖
分解后的函数依赖集与分解前保持一致。
又称依赖等价原则, 保证分解前后数据语义的一致性。