为什需要 DataBase?

假设我们要存储数据:

  • 艺术家(Artists)信息
  • 艺术家发行的专辑(Albums)信息

我们可以用连个 CSV 文件分别存储艺术家和专辑信息,然后用程序来解析和序列化相关数据。

艺术家信息表:

1
2
3
"Wu Tang Clan",1992,"USA"
"Notorious BIG",1992,"USA"
"Ice Cube",1989,"USA"

专辑信息表:

1
2
3
"Enter the Wu Tang","Wu Tang Clan",1993
"St.Ides Mix Tape","Wu Tang Clan",1994
"AmeriKKKa's Most Wanted","Ice Cube",1990

假设我们想知道 “Ice Cube 在哪年首发”,就会写这样的查询脚本:

1
2
3
4
for line in file:
record = parse(line)
if record[0] == "Ice Cube":
print(int(record[1]))

但这种简单的方案有很多缺陷:

  • 数据的质量方面
    • 很难保证同一个艺术家发行的每条专辑信息中,艺术家字段一致
    • 很难阻止用户在年份字段写入不合法的字符串
    • 很难优雅地处理一张专辑由多个艺术家共同发行的情况
  • 实现方面
    • 查询一条特定的记录,效率低
    • 当有多个应用使用该 CSV 数据库
      • 查询脚本需要重复写
      • 多个线程一起写时,如何保证数据一致性
  • 数据持久
    • 正在写记录时遇到宕机(稳定性)
    • 如何复制数据库到多台机器上来保证高可用性(数据分片问题)

以上缺陷迫使我们需要升级 CSV 数据库,于是就有了专业的数据库系统 「DBMS」。

DBMS 的提出

分离逻辑层和物理层

所有系统都会产生数据,因此数据库几乎是所有系统都不可或缺的模块。在早期,各个项目各自造轮子,因为每个轮子都是为应用量身打造,这些系统的「逻辑层(logical)」和「物理层(physical)」普遍耦合度很高。

逻辑层(logical layer)

  • 逻辑层是数据库的中间层,它为用户和应用程序提供了一个抽象的数据模型,用户可以在这个层次上定义和操作数据。
  • 在这个层次上,用户定义表、视图、索引等数据库对象,以及它们之间的关系(如主键、外键)。
  • 逻辑层屏蔽了物理存储的细节,用户可以专注于数据的逻辑结构和关系,而不需要关心数据是如何在磁盘上存储的。
  • 数据库的查询语言(如SQL)通常在这个层次上操作,允许用户查询、更新、插入和删除数据。

物理层(physical layer)

  • 物理层是数据库的最底层,它涉及到数据在存储介质上的实际表示和存储方式。
  • 这个层次关心的是数据的物理存储,包括数据文件、索引文件、日志文件等在磁盘上的布局。
  • 数据库管理系统(DBMS)会负责管理这些物理存储的细节,如数据的读写、存储结构(如行存储或列存储)、数据压缩、加密等。
  • 用户通常不需要直接与物理层交互,这些细节被数据库系统自动处理。

后面还有「视图层(view layer)」,用来解决高效分析作用。

视图层(view layer)

  • 视图层是数据库的最顶层,它提供了一个更高级别的抽象,允许用户定义和使用视图。
  • 视图是从一个或多个表中派生出来的虚拟表,它们可以简化复杂的查询,隐藏数据的复杂性,或者限制对特定数据的访问。
  • 用户可以通过视图来访问数据,而不需要直接操作底层的表结构。

Ted Codd 发现这个问题后,提出 DBMS 的抽象(Abstraction):

用简单的、统一的数据结构存储数据

通过高级语言操作数据

逻辑层和物理层分离,系统开发者只关心逻辑层,而 DBMS 开发者才关心物理层。

数据模型(Data Modle)

在逻辑层中,我们通常需要对所需存储的数据进行建模。如今,市面上有的数据模型包括:

  • Relational => 大部分 DBMS 属于关系型,也是本课讨论的重点
  • Key/Value => NoSQL(Not only SQL)
  • Graph => NoSQL
  • Document => NoSQL
  • Column-family => NoSQL
  • Array/Matrix => 机器学习( Machine Learning )
  • Hierarchical => Obsolete / Rare
  • Network => Obsolete / Rare

关系模型(Relational Model)

Relation & Tuple

每个 Relation 都是一个无序集合(unordered set),集合中的元素称为 tuple,每个 tuple 由一组属性构成,这些属性在逻辑上通常有内在联系。

在数据库管理系统(DBMS)中,特别是在关系数据库中,”tuples” 这个词通常指的是关系表中的一行记录。在SQL(Structured Query Language)中,我们更常用 “row” 或 “record” 来描述单个数据项,但在某些文献和数据库理论中,”tuple” 这个词仍然被使用。

以下是对 SQL 中的 “tuples” 的追加理解:

  • 数据结构:在关系数据库理论中,一个关系(即表)可以被看作是一个二维数组,其中每一行(tuple)代表一个数据项,每一列代表一个属性或字段。
  • 数据单元:每个 tuple 包含了一组相关的数据,这些数据对应于表中的列。例如,在一个员工表中,一个 tuple 可能包含一个员工的ID、姓名、年龄、职位等信息。
  • 无序性:在关系数据库中,tuples 通常被认为是无序的。这意味着,尽管在数据库表中数据是按行排列的,但理论上,这些行的顺序并不重要,因为每个 tuple 都是唯一的,并且可以通过主键来唯一标识。
  • 操作对象:在执行 SQL 查询时,数据库操作(如选择、插入、更新、删除)通常都是针对 tuples 进行的。例如,一个 SELECT 语句会从表中检索特定的 tuples,而一个 DELETE 语句会从表中移除特定的 tuples。
  • 关系代数中的元素:在关系代数中,tuples 是操作的基本元素。关系代数是一种数学语言,用于形式化地表达对关系数据库的操作。在关系代数中,操作如选择(σ)、投影(π)和连接(⋈)都是定义在 tuples 上的。
  • 与行的区别:虽然在实际的 SQL 使用中,我们通常说 “row” 而不是 “tuple”,但这两个词在概念上是等价的。”Tuple” 这个词更多地用于理论讨论和某些数据库文献中,而 “row” 更常用于日常的数据库操作和 SQL 语句中。

举例:

1
select id,name from student

其中,返回的每一行,如:(1, 'Alice'),(2, 'Bob') 都是 tuple。

Primary Keys

primary key 在一个 Relation 中唯一确定一个 tuple,如果你不指定,有些 DBMSs 会自动帮你生成 primary key。

Foreign Keys

foreign key 唯一确定另一个 relation 中的一个 tuple

利用这些基本概念,我们就可以利用第三张表,ArtistAlbum,来解决专辑与艺术家的 1 对多的关系问题:

1
id, name, year, country
1
id, name, year
1
artist_id, album_id

Data Manipulation Languages (DML)

在 Relational Model 中从数据库中查询数据通常有两种方式:「过程式查询语言(Procedural)」 与 「非过程式查询语言(NonProcedural)」:

过程式查询语言(Procedural) 即 relational algebra:

  • 过程式查询语言要求用户详细描述如何执行查询操作。用户需要指定数据的检索路径和操作步骤。
  • 这类语言通常更接近于底层的数据库操作,比如关系代数(Relational Algebra)就是一种过程式查询语言。在关系代数中,用户通过组合不同的操作符(如选择、投影、连接等)来表达查询的逻辑和步骤。
  • 过程式语言的优点是提供了对查询执行过程的精细控制,但缺点是对于非技术用户来说可能难以理解和使用。

非过程式查询语言(NonProcedural)即 relational calculus:

  • 非过程式查询语言只需要用户指定想要查询的数据是什么,而不需要关心数据是如何被检索和处理的。用户只需要描述数据的需求,而具体的检索策略和执行步骤由数据库管理系统来决定。
  • SQL(Structured Query Language)是一种非常流行的非过程式查询语言。用户通过SQL语句来表达查询需求,例如“选择所有年龄大于30岁的员工”,而具体的数据检索路径和优化策略则由数据库管理系统自动处理。
  • 非过程式语言的优点是易于理解和使用,用户不需要深入了解数据库的内部结构和操作细节。但缺点是用户对查询执行过程的控制较少。

Tips:
NonProcedural SQL 没有那么多复杂的关系代数(relational algebra),一切关系基本上是靠 join 等操作实现代数操作。

使用哪种方式是具体的实现问题,与 Relational Model 本身无关。

Relational Algebra

relational algebra 是基于 set algebra 提出的,从 relation 中查询和修改 tuples 的一些基本操作,它们包括:

  • Select ( σ ):选择
  • Projection ( π ):投影
  • Union ( ∪ ):并集
  • Intersection ( ∩ ):交集
  • Difference ( − ):差集
  • Product ( × ):笛卡尔积
  • Join ( ⨝ ):连接
  • Rename ( ρ ):重命名
  • Assignment ( R←S ):赋值
  • Duplicate Elimination ( δ ):消除重复
  • Aggregation ( γ ):聚合
  • Sorting ( τ ):排序
  • Division ( R÷S ):除法

将这些操作串联起来,我们就能构建更复杂的操作

注意:
使用 Relation Algebra 时,我们实际上指定了执行策略,如:

它们所做的事情都是 “返回 R 和 S Join 后的结果中,b_id 等于 102 的 tuples”。

虽然 Relational Algebra 只是 Relational Model 的具体实现方式,但在之后的课程将会看到它对查询优化、执行的帮助。

参考:

[1]:https://zhenghe.gitbook.io/open-courses/cmu-15-445-645-database-systems/relational-data-model

[2]:https://15445.courses.cs.cmu.edu/fall2018/slides/01-introduction.pdf

[3]:https://www.youtube.com/watch?v=APqWIjtzNGE&list=PLSE8ODhjZXjYDBpQnSymaectKjxCy6BYq&index=2