Lecutre 1

参考文档

理解一些数据库发展

混淆的概念:

数据库(Database) 和 数据库管理系统(DBMS) 是两个不同但密切相关的概念

  1. Database: 存储的数据本体
  2. DBMS: 管理数据库的软件

数据库是你要保存的内容, 数据库管理系统是帮你存、查、改这些内容的工具。

为什么不能仅仅依赖内存和硬盘呢?

硬件只是存储的“位置”,但数据库解决的是**“怎么存、怎么查、怎么组织”**的问题。

最简单的数据库系统

“文件 + 代码”,

id,name,age,email
1,张三,20,zhangsan@example.com
2,李四,22,lisi@example.com
3,王五,19,wangwu@example.com

对数据进行操作:


open file "users.csv" as file
read first line from file // 表头
columns = split(line, ",")

while not end_of_file(file):
    line = read line from file
    if line is empty:
        continue
    fields = split(line, ",")
    user = {}
    for i in range 0 to length(columns) - 1:
        user[columns[i]] = fields[i]
    print("User ID:", user["id"], "Name:", user["name"], "Email:", user["email"])
close file

问题来了:

  1. 随着行数的增加它会越来越慢

平面文件(Flat File)存储的局限性 数据访问效率低:

  1. 必须顺序扫描整个文件(O(n)复杂度)

  2. 数据完整性无保障:

  3. 没有约束检查(如年份是否合法)

  4. 容易出现数据不一致

  5. 多用户同时访问时可能产生冲突

  6. 如何保证发生崩溃时我们的数据安全?

  7. 多应用共享文件存储时的耦合与混乱问题 :

多个程序读取用户数据文件
users.csv 存在 /home/data/users.csv,被两个程序共享读取:

App A:用于展示用户信息

App B:用于统计年龄分布

文件路径一变,两个程序都挂

App A 改了字段顺序(先 name 后 id),App B 解析出错: 一旦修改顺序 B虽然能取出数据 但是数据并不对应!

有人手动编辑 CSV,造成数据不一致(比如缺字段)

通过这个例子能理解到:

为什么需要数据库系统(解决平面文件的诸多问题)

从简单方案出发理解数据库组件的必要性

数据库查询与过程式代码的根本区别

数据库系统就会 让我们不用去担心上述问题!


数据库中的数据模型(Data Models)

早期层次结构和网状结构的问题:

什么叫紧密耦合? 应用程序必须清楚数据库的具体结构和存储方式,而且访问逻辑写死在代码里。

必须要移除的三个依赖:

Ordering Dependence

应用程序依赖于数据在物理存储上的顺序,假设数据的逻辑顺序与物理存储顺序一致。

Indexing Dependence:

应用程序不仅依赖于数据本身,还依赖于数据的索引结构,导致应用和索引耦合过紧。

Access Path Dependence:

一旦树状或网络结构发生变化(比如节点增加、关系调整、层级变动), 应用程序中的访问逻辑就会失效或出错。

抽象思想:

抽象之所以能解耦,是因为它隔离了“使用者”和“实现者”,让彼此通过稳定的接口交互,不直接依赖内部细节。

一 . Relational(关系模型)

关系 = 元组的集合(关系是一个二维表,表中的每一行叫“元组”(tuple),所有元组组成一个集合(无序且不重复)。)

属性(字段)集合: 关系的每个列是属性,属性有对应的取值域(Domain)

关系模型把_“数据结构”和“数据存储”解耦了。_

你只关心“表结构”和“数据关系”,数据库系统自由决定如何高效地存储和访问这些数据。

也就是

"你写的只是“查年龄大于 20 的人”,数据库系统在背后可能用了 B+ 树索引、哈希缓存、磁盘页加载、并发调度等几十个底层机制来高效完成。"

表(Table/Relation): 数据以二维表格形式组织

行(Row/Tuple): 表中的一条记录

列(Column/Attribute): 表中的字段

主键(Primary Key): 唯一标识表中每一行的列或列组合

关于主键:

主键必须手动定义,数据库不会默认添加。

自增列(AUTO_INCREMENT)≠ 主键:自增只是生成值的方式,主键约束仍需明确声明。

没有主键的表是合法的,但会带来数据完整性和性能问题。

外键(Foreign Key): 外键是一种用来关联表与表之间关系的约束,保证引用的合法性。:

关于外键:

建模现实世界的关联关系 比如订单表里的 user_id 外键关联用户表的主键 id,表达“这个订单属于哪个用户”。

中间关联表:

这个中间表是多对多实体关系的标准表达方式,它用最简洁的结构清晰地表示了每一个艺术家与专辑之间的对应关系。

为什么要引入中间表:

因为你要表示的是多对多关系,单靠两个表无法干净、规范、安全地表达这个关系,所以必须引入一个中间表。

数组字段:


Album 表:
id | name                   | artist_ids
----------------------------------------
22 | St. Ides Mix Tape      | [101, 102, 103]

第一范式要求:

每一列都是原子值(不可再拆的单个值) 也就是一张表的每一行、每一列,只能有一个值,不能是数组、集合、结构体等复杂类型 数组,不是原子值

索引:

索引是“数据库存储引擎内部维护的一种特殊数据结构”,它和普通字段不同,不是属性,而是一种加速访问用的结构性机制。

为字段创建索引,避免全表扫描!

PG 默认索引结构: B-Tree 同样也支持其它的索引结构

常用的 表格结构:行-列: 比如 MySQL、PostgreSQL

二. NoSQL

模型类型 | 简要解释 | 常见代表数据库

Key/Value | 类似哈希表:key → value | Redis、Riak Graph | 图结构:节点 + 边 | Neo4j、JanusGraph Document / XML / Object | 类 JSON / 文档型结构 | MongoDB、CouchDB Wide-Column / Column-family | 表但按列族存储 | Cassandra、HBase

应对关系型数据库在高并发、大数据、非结构化数据方面的限制。

关系代数

关系代数中的每一个操作/函数都对输入集合(关系是一个元组的集合 )进行操作,并返回一个输出集合作为结果!!!

  1. 集合运算符
  2. 数据库特定运算符
  3. 几何函数

σ(Condition)(R) -> "从关系 R 中选择_满足条件 Condition 的元组_" π (attribute-list) (R) -> "从关系 R 中的所有元组中_仅选择属性列表中给出的属性值_" A ⋈C B = σC ( A × B ) -> 对笛卡尔积结果按条件C进行筛选(选择)