4. Relational DB
第一部分:数据库模型的演进
| 模型 | 核心思想 | 代表系统 | 优点 | 缺点 |
|---|---|---|---|---|
| 层次模型 | 数据组织成树形结构,每个节点只有一个父节点。 | IBM IMS | 结构清晰,查询速度快(对于特定路径)。 | 数据冗余大,结构不灵活,查询复杂(需要遍历路径)。 |
| 网状模型 | 数据组织成图结构,节点可以有多个父节点。 | GE IDS | 比层次模型更能反映现实世界复杂的多对多关系。 | 极其复杂!程序员必须像“导航员”一样,通过指针在数据网络中穿梭,编程负担重。 |
| 关系模型 | 数据组织成二维表(关系),通过值来关联。 | 所有现代数据库 | 数据独立性高,声明式语言(SQL)简单强大,坚实的数学理论基础。 | 在早期,性能被认为不如前两者(现已通过优化技术解决)。 |
关键人物与思想突破: - Ted Codd:1970年发表论文《A Relational Model of Data for Large Shared Data Banks》。 - 核心贡献:将数据的逻辑结构(我们看到的表)与物理存储(数据在磁盘上的存放方式)彻底分离。程序员不再需要关心数据是如何存储和连接的,只需关心数据本身。
**第二部分:关系模型的数学基础
1. 理论基础:谓词逻辑与集合论
- 谓词逻辑:关系模型的核心思想。我们用表来表述关于世界的命题。
- 示例:
学生表中的一行(101, ‘张三‘, ‘计算机’)可以看作一个命题:“存在一个学号为101,名叫张三的学生,他主修计算机科学。” -
声明式 vs 过程式:
- 网状/层次模型(过程式):“首先找到第一个学生节点,然后沿着‘选修’指针找到他所有的课程节点,再沿着‘课程’指针取出课程名...” (告诉计算机怎么做)
- 关系模型(声明式):“给我所有选修了‘数据库’课程的学生名字。” (告诉计算机要什么)
-
关系演算:基于谓词逻辑的查询理论,是SQL语言的理论先驱。它描述了想要的结果应该满足什么条件,而不指定如何获取。
2. 核心概念精讲
- 域:一组具有相同数据类型的值的集合。例如:
性别域 {‘男‘, ’女‘},学号域 {所有可能的学号字符串}。 -
作用:规定了属性的取值范围。
-
笛卡尔积:给定一组域
D1, D2, ..., Dn,它们的笛卡尔积是所有这些域中元素的所有可能组合。 - 示例:域
D1 = {A, B},D2 = {1, 2}, 则D1 x D2 = {(A,1), (A,2), (B,1), (B,2)}。 -
它本身通常包含大量无意义的元组。
-
关系:笛卡尔积的一个有意义的子集。
- 你的比喻非常准确:一张表。
- 元组:表中的一行。
- 属性:表中的一列。
- 关系模式:关系的结构描述,通常表示为
关系名(属性1, 属性2, ...)。例如:学生(学号, 姓名, 专业)。
第三部分:关系代数——操作的数学语言
关系代数定义了一组在关系(表)上操作的运算符,其输入和输出都是关系。这正是它封闭性和强大的原因。
基本运算符
-
选择
- 符号: σ
- 作用: 从关系R中水平地选出满足给定条件P的元组。
- 类比SQL:
WHERE子句。 - 示例:
σ_(专业=‘计算机‘)(学生)等价于SELECT * FROM 学生 WHERE 专业=‘计算机‘;
-
投影
- 符号: Π
- 作用: 从关系R中垂直地选出指定的属性列,并自动去除重复的元组。
- 类比SQL:
SELECT后面指定列。 - 示例:
Π_(姓名, 专业)(学生)等价于SELECT DISTINCT 姓名, 专业 FROM 学生; - 注意:因为关系是集合,所以会自动去重。
-
并、差、交
- 符号: ∪, -, ∩
- 前提: 两个关系必须是并相容的,即属性数目相同,且对应的属性域相同。
- 作用: 对两个关系进行集合运算。
-
笛卡尔积
- 符号: ×
- 作用: 将两个关系R和S的所有元组进行两两组合。
- 示例: 如果R有3行,S有2行,则 R × S 有 6行。
- 注意: 结果中可能包含大量无意义的数据,通常需要后续的选择操作来过滤。
核心拓展:连接操作
- 符号: ⋈
- 本质: 连接 = 笛卡尔积 + 选择。
- 分类:
- θ连接: 选择条件P是任意的。
R ⋈_(P) S - 等值连接: θ连接的特例,条件P只包含等号
=。 - 自然连接: 最常用的一种等值连接。
- 自动对两个关系中所有同名同域的属性进行等值匹配。
- 结果中同名属性只保留一份。
示例: 假设有: 学生(学号, 姓名) 选课(学号, 课程号, 成绩)
自然连接:学生 ⋈ 选课 1. 先做笛卡尔积:学生 × 选课,结果有5列 (学号_s, 姓名, 学号_x, 课程号, 成绩)。 2. 自动应用选择条件:学号_s = 学号_x。 3. 在结果中合并重复列,最终得到4列:(学号, 姓名, 课程号, 成绩)。
这等价于SQL: SELECT * FROM 学生 NATURAL JOIN 选课;
第四部分:关系代数表达式与SQL的对应
你的笔记提到“多个算子结合嵌套”,这正是关系代数的威力所在,也是SQL查询的构建方式。
一个复杂查询的分解:
查询目标:“找出选修了‘数据库’课程的学生的姓名。”
关系代数表达式: Π_(姓名) ( σ_(课程名=‘数据库‘) (课程) ⋈ 选课 ⋈ 学生 ) )
分步解析: 1. σ_(课程名=‘数据库‘)(课程): 先从课程表中找到“数据库”这门课的信息。 2. ... ⋈ 选课 ⋈ 学生: 将上一步的结果与选课表自然连接(通过课程号),再与学生表自然连接(通过学号),这样就得到了所有选修了“数据库”课程的学生完整信息。 3. Π_(姓名)(...): 最后从连接后的大表中,投影出我们最终需要的姓名列。
对应的SQL语句:
SELECT DISTINCT 学生.姓名
FROM 学生
JOIN 选课 ON 学生.学号 = 选课.学号
JOIN 课程 ON 选课.课程号 = 课程.课程号
WHERE 课程.课程名 = ‘数据库‘;
NATURAL JOIN 可以省略 ON 条件) 总结与复习建议
- 理解脉络:记住从“导航”到“声明”的范式转变,这是理解关系数据库优势的基石。
- 掌握核心:深刻理解关系、域、笛卡尔积这些基本概念。
- 熟练操作:将选择σ、投影Π、连接⋈这三个最核心的运算符,与SQL中的
WHERE、SELECT、JOIN建立牢固的对应关系。 - 练习表达:尝试将复杂的中文查询需求,先写成关系代数表达式,再翻译成SQL。这是检验你是否真正理解的绝佳方法。