数据库系统原理与应用教程(016)—— 关系的规范化(一)

数据库系统原理与应用教程(016)—— 关系的规范化(一)

为了使关系模式设计的方法更加完善,人们提出了关系的规范化理论。范式是规范化的关系模式,由于规范化程度不同,产生了不同的范式。满足最基本规范化的关系模式叫第一范式,在第一范式的基础上,关系模式再满足其他一些约束条件就是第二范式、第三范式、BC 范式、第四范式、第五范式等。

一个低一级的关系范式通过模式分解可以转换为高一级范式的关系模式,这种过程称为关系的规范化。

一、关系模式规范化的必要性

关系数据库的设计主要是关系模式的设计。将关系模式规范化,使之达到较高的范式,是设计关系模式的主要途径。

1、关系模式应满足的基本要求
(1)元组的每个分量必须是不可分的数据项

这是关系的基本性质之一,如果不能满足,则表格就不是关系。如果表格中包含有组合属性,必须进行分解,使之转换为基本数据项。

(2)数据库中的数据冗余应尽可能少

数据冗余是指同一个数据重复存储。数据冗余会浪费大量的存储空间,由于数据重复存储,修改数据时可能造成数据不一致,增加数据维护的工作量。数据冗余还会造成数据查询和统计的困难,导致错误的结果。

对于关系数据库来说,实体之间的联系是通过外码来实现的,而外码就是一种数据冗余,外码是关系数据库不可消除的数据冗余。在设计数据库时,除了外码这种数据冗余之外,应消除其他不必要的数据冗余。

(3)关系数据库不能因为数据更新操作而引起数据不一致问题

如果数据库中存在不必要的数据冗余,同一个数据在多个地方重复存储。当执行数据修改时,这些冗余数据可能出现有的被修改,有的没有修改,从而造成数据不一致问题。数据不一致问题影响了数据的完整性。

数据不一致问题是由数据冗余造成的,如果消除了不必要的数据冗余,数据不一致问题也会得到解决。

(4)数据库中的数据不能在执行数据插入时出现插入异常问题

所谓插入异常是指希望插入的数据由于不能满足数据库完整性的要求,而不能正常地被插入到数据库。通俗地说插入异常就是应该插入的数据无法插入。例如下面的表格就存在数据冗余和插入异常问题:

教学关系:

学号姓名年龄性别系名系主任课程名成绩
98001李华20计算机系王民程序设计88
98001李华20计算机系王民数据结构74
98001李华20计算机系王民数据库82
98001李华20计算机系王民电路65
98002张平21计算机系王民程序设计92
98002张平21计算机系王民数据结构82
98002张平21计算机系王民数据库78
98002张平21计算机系王民电路83
98003陈兵20数学系赵敏高等数学72
98003陈兵20数学系赵敏数据结构94
98003陈兵20数学系赵敏数据库83
98003陈兵20数学系赵敏离散数学87

以上的教学关系中,学生的信息和系的信息都是冗余的。其中,每个学生的信息冗余 4 次,计算机系的信息冗余 8 次,数学系的信息冗余 4 次。该表的主键为(学号,课程名),当一个系没有学生时,由于学号为空,系的信息无法插入;当一个学生没有选课时,由于课程名为空,则学生的信息无法插入;当一门课程没有学生选修,由于学号为空,导致课程的信息无法插入。这些都属于插入异常。

(5)数据库中的数据不能在执行删除操作时出现删除异常问题

删除异常是指在删除某些数据的同时把其他数据也删除了。通俗的说,删除异常就是删除了不该删除的信息。比如上面的教学关系中,如果要删除学生陈兵的信息,当陈兵的信息被删除时,数学系的信息也被删除了;当选修某门课程的学生的信息被删除时,该门课程的信息也被删除;当某个学生学习的所有的课程的信息被删除,则该学生的信息也会被删除。

(6)数据库设计应考虑查询要求,数据组织应合理

在数据库设计时,不仅要考虑自身的结构完整性,还要考虑数据的使用要求。为了使数据查询和数据处理高效简洁,比如对那些查询实时性要求高、操作频度大的数据,可以通过视图、索引和适当增加数据冗余的方法,增加数据库的可用性。

二、关系规范化的主要方法

如果一个关系模式存在数据冗余、插入异常和删除异常,其主要原因是数据库设计时没有按照“一事一地”的原则,多种信息存放到一个表中造成的。因此,关系规范化的主要方法就是对关系模式进行分解。

1、关系模式分解的原则

关系模式分解的原则:一事一地,保持联系!

一事一地:一个实体集分解为一个关系。

保持联系:分解之后实体集之间联系的信息不能丢失。

2、关系模式分解的步骤

以教学关系为例,上面的教学关系的关系模式为:

教学(学号,姓名,年龄,性别,系名,系主任,课程名,成绩)

步骤一:分析关系模式中包含哪些的实体集?

经过分析,教学关系包含三种实体集:学生,系,课程

步骤二:给每个实体集添加编码作为将来分解后的主键。

教学关系为每个实体集添加主键后如下:

教学(学号,姓名,年龄,性别,系编号,系名,系主任,课程号,课程名,成绩)

步骤三:按照一事一地的原则根据实体集对关系模式进行分解。

结果如下:

学生(学号,姓名,年龄,性别)

系(系编号,系名,系主任)

课程(课程号,课程名)

步骤四:分析实体集之间的联系,使用外码表示。

经过分析可知,系和学生之间存在一对多联系,在学生中添加系编号来表示。学生和课程之间存在多对多联系,增加一个选课表来表示。

结果如下:

系(系编号,系名,系主任)

学生(学号,姓名,年龄,性别,系编号)

课程(课程号,课程名)

选课(学号,课程号,成绩)

分解之后的关系模式内容如下:

系编号系名系主任
D01计算机系王民
D02数学系赵敏

学生

学号姓名年龄性别系编号
98001李华20D01
98002张平21D01
98003陈兵20D02

课程

课程号课程名
C01程序设计
C02数据结构
C03数据库
C04电路
C05高等数学
C06离散数学

选课

学号课程号成绩
98001C0188
98001C0274
98001C0382
98001C0465
98002C0192
98002C0282
98002C0378
98002C0483
98003C0572
98003C0294
98003C0383
98003C0687

分解之后的关系模式有效解决了上述问题。除了外码之外,消除了不必要的数据冗余。

对于系来说,即使一个系没有学生也可以插入该系的信息,反之,即使把所有学生的信息全部删除,系的信息也不会丢失。

对于学生来说,即使没有选修任何课程,学生的信息也可以插入。反之,即使把该学生的选课信息全部删除,学生的信息也不会丢失。

对于课程来说,即使该课程没有任何学生选修,课程的信息也可以插入。反之,即使把选修该课程的所有信息删除,该课程的信息也不会丢失。

以上关系模式在 MySQL 中实现如下:

/*
-- 系
create table dept(
    dept_id char(3) primary key,
    dept_name char(20),
    xzr char(20)
);

insert into dept values('D01','计算机系','王民');
insert into dept values('D02','数学系','赵敏');

-- 学生
create table stu(
    stu_id char(5) primary key,
    stu_name char(20),
    age int,
    gender char(4),
    dept_id char(3)
);

insert into stu values('98001','李华',20,'男','D01');
insert into stu values('98002','张平',21,'女','D01');
insert into stu values('98003','陈兵',20,'男','D02');

-- 课程
create table course(
    c_id char(3) primary key,
    c_name char(20)
);

insert into course values('C01','程序设计');
insert into course values('C02','数据结构');
insert into course values('C03','数据库');
insert into course values('C04','电路');
insert into course values('C05','高等数学');
insert into course values('C06','离散数学');

-- 选课
create table sc(
    stu_id char(5),
    c_id char(3),
    grade int
);

insert into sc values('98001','C01',88);
insert into sc values('98001','C02',74);
insert into sc values('98001','C03',82);
insert into sc values('98001','C04',65);
insert into sc values('98002','C01',92);
insert into sc values('98002','C02',82);
insert into sc values('98002','C03',78);
insert into sc values('98002','C04',83);
insert into sc values('98003','C05',72);
insert into sc values('98003','C02',94);
insert into sc values('98003','C03',83);
insert into sc values('98003','C06',87);

*/

mysql> select * from dept;
+---------+--------------+--------+
| dept_id | dept_name    | xzr    |
+---------+--------------+--------+
| D01     | 计算机系     | 王民   |
| D02     | 数学系       | 赵敏   |
+---------+--------------+--------+
2 rows in set (0.01 sec)

mysql> select * from stu;
+--------+----------+------+--------+---------+
| stu_id | stu_name | age  | gender | dept_id |
+--------+----------+------+--------+---------+
| 98001  | 李华     |   20 || D01     |
| 98002  | 张平     |   21 || D01     |
| 98003  | 陈兵     |   20 || D02     |
+--------+----------+------+--------+---------+
3 rows in set (0.00 sec)

mysql> select * from course;
+------+--------------+
| c_id | c_name       |
+------+--------------+
| C01  | 程序设计     |
| C02  | 数据结构     |
| C03  | 数据库       |
| C04  | 电路         |
| C05  | 高等数学     |
| C06  | 离散数学     |
+------+--------------+
6 rows in set (0.00 sec)

mysql> select * from sc;
+--------+------+-------+
| stu_id | c_id | grade |
+--------+------+-------+
| 98001  | C01  |    88 |
| 98001  | C02  |    74 |
| 98001  | C03  |    82 |
| 98001  | C04  |    65 |
| 98002  | C01  |    92 |
| 98002  | C02  |    82 |
| 98002  | C03  |    78 |
| 98002  | C04  |    83 |
| 98003  | C05  |    72 |
| 98003  | C02  |    94 |
| 98003  | C03  |    83 |
| 98003  | C06  |    87 |
+--------+------+-------+
12 rows in set (0.01 sec)

/*
select s.stu_id, s.stu_name, s.age, s.gender, d.dept_name, d.xzr, c.c_name, grade
from stu s, dept d, course c, sc
where s.dept_id = d.dept_id and s.stu_id = sc.stu_id and c.c_id = sc.c_id;
*/

mysql> select s.stu_id, s.stu_name, s.age, s.gender, d.dept_name, d.xzr, c.c_name, grade
    -> from stu s, dept d, course c, sc
    -> where s.dept_id = d.dept_id and s.stu_id = sc.stu_id and c.c_id = sc.c_id;
+--------+----------+------+--------+--------------+--------+--------------+-------+
| stu_id | stu_name | age  | gender | dept_name    | xzr    | c_name       | grade |
+--------+----------+------+--------+--------------+--------+--------------+-------+
| 98001  | 李华     |   20 || 计算机系     | 王民   | 程序设计     |    88 |
| 98001  | 李华     |   20 || 计算机系     | 王民   | 数据结构     |    74 |
| 98001  | 李华     |   20 || 计算机系     | 王民   | 数据库       |    82 |
| 98001  | 李华     |   20 || 计算机系     | 王民   | 电路         |    65 |
| 98002  | 张平     |   21 || 计算机系     | 王民   | 程序设计     |    92 |
| 98002  | 张平     |   21 || 计算机系     | 王民   | 数据结构     |    82 |
| 98002  | 张平     |   21 || 计算机系     | 王民   | 数据库       |    78 |
| 98002  | 张平     |   21 || 计算机系     | 王民   | 电路         |    83 |
| 98003  | 陈兵     |   20 || 数学系       | 赵敏   | 高等数学     |    72 |
| 98003  | 陈兵     |   20 || 数学系       | 赵敏   | 数据结构     |    94 |
| 98003  | 陈兵     |   20 || 数学系       | 赵敏   | 数据库       |    83 |
| 98003  | 陈兵     |   20 || 数学系       | 赵敏   | 离散数学     |    87 |
+--------+----------+------+--------+--------------+--------+--------------+-------+
12 rows in set (0.02 sec)

  • 6
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
针对23种设计模式,分别写了demo并画了类图帮助理解。 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。 行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。 其实还有两类:并发型模式和线程池模式。 二、设计模式的六大原则 1、开闭原则(Open Close Principle) 开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类,后面的具体设计中我们会提到这点。 2、里氏代换原则(Liskov Substitution Principle) 里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范。—— From Baidu 百科 3、依赖倒转原则(Dependence Inversion Principle) 这个是开闭原则的基础,具体内容:真对接口编程,依赖于抽象而不依赖于具体。 4、接口隔离原则(Interface Segregation Principle) 这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。还是一个降低类之间的耦合度的意思,从这儿我们看出,其实设计模式就是一个软件的设计思想,从大型软件架构出发,为了升级和维护方便。所以上文中多次出现:降低依赖,降低耦合。 5、迪米特法则(最少知道原则)(Demeter Principle) 为什么叫最少知道原则,就是说:一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。 6、合成复用原则(Composite Reuse Principle) 原则是尽量使用合成/聚合的方式,而不是使用继承。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

睿思达DBA_WGX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值