欢迎来到关系型数据库的世界!
数据库是几乎所有现代业务的支柱,从你最喜欢的流媒体服务到学校的教务系统,无处不在。本章将深入探讨关系型数据库(Relational Databases),它们的核心任务是以高效且合乎逻辑的方式组织数据,以便计算机能够快速、可靠地检索信息。
别担心“规范化(Normalisation)”等术语听起来很复杂——我们将通过简单的类比为你拆解这些概念。读完本节,你将理解数据模型是如何构建的、表与表之间是如何链接的,以及如何使用强大的 SQL 语言与数据库进行“对话”。准备好成为一名数据架构师了吗?让我们开始吧!
1. 概念数据模型与实体关系建模
什么是实体(Entity)?
实体是一个现实世界中的对象或概念,我们希望存储关于它的数据。你可以把它想象成数据库结构中的“核心名词”。
示例:顾客(CUSTOMER)、产品(PRODUCT)、订单(ORDER)、课程(COURSE)。
属性(Attributes / Fields)
属性是实体的特征或属性。这些就是你实际存储的信息片段。
在已实现的数据库(真实的软件系统)中,属性被称为字段(fields)或列(columns)。
示例:学生(STUDENT)实体可能包含以下属性:学生ID(StudentID)、姓名(Name)、出生日期(DateOfBirth)。
实体标识符(主键 - Primary Key)
实体标识符(或主键,PK)是一个或多个属性,用于唯一标识实体(表)中的每一条记录(行)。
在数据建模中,我们通过给属性加下划线来表示实体标识符。
示例:完整的实体描述书写方式如下:
STUDENT(StudentID, Name, DateOfBirth)
有时,唯一标识符必须由多个属性组合而成。这被称为复合实体标识符(Composite Entity Identifier)或复合主键(Composite Primary Key)。
示例:如果班级名单中没有学生ID,你可以使用 (FirstName, LastName, DateOfBirth) 来唯一确定一个人。
关系程度(Degrees of Relationship)
关系定义了实体之间如何互动。关系程度告诉我们一个实体中的实例与另一个实体中的实例之间存在多少关联。
在实体关系图(ERD)中,这些通常用特定的符号表示:
一对多(One-to-Many, 1:M)
实体A中的一个实例与实体B中的零个、一个或多个实例相关联。但实体B中的一个实例仅与实体A中的一个实例相关联。
类比:一名系主任(HEAD OF DEPARTMENT)管理多名教师(TEACHERS)。
符号示例:HEAD_OF_DEPT --< TEACHER
多对一(Many-to-One, M:1)
这是“一对多”的反向关系。
类比:多名教师(TEACHERS)向一名系主任(HEAD OF DEPARTMENT)汇报。
符号示例:TEACHER >-- HEAD_OF_DEPT
一对一(One-to-One, 1:1)
实体A中的一个实例与实体B中的恰好一个实例相关联,反之亦然。
类比:一个人(PERSON)拥有一本护照(PASSPORT)。一本护照只属于一个人。
符号示例:PERSON ---- PASSPORT
多对多(Many-to-Many, M:M)
实体A中的一个实例可以与实体B中的多个实例相关联,反之亦然。
注意:在实际的关系型数据库设计中,必须将 M:M 关系分解为两个 1:M 关系(通常使用连接表/中间表),但你必须熟悉这种概念模型。
类比:一名学生(STUDENT)注册多门课程(COURSES)。一门课程由多名学生选修。
符号示例:STUDENT >--< COURSE
2. 关系型数据库的核心概念
关系型数据库概念
关系型数据库是一组结构化数据项的集合,以正式描述的表(关系)形式组织。我们可以通过多种方式访问或重组这些数据,而无需重新组织数据库表本身。
其核心理念是:数据存储在不同的表中,并通过称为外键(Foreign Keys)的特殊属性链接在一起。
抽象术语与实现术语的对应
在讨论抽象数据模型时,我们使用特定的术语。而在讨论实际实现的数据库时,我们使用不同的(但等效的)术语:
- 关系 (Relation) / 表 (Table): 存储数据的数据库表。
- 属性 (Attribute) / 字段 (Field): 表中的列标题。
- 实体标识符 (Entity Identifier) / 主键 (Primary Key, PK): 唯一标识一行的字段。
外键(Foreign Key, FK)
外键是表中指向另一个表主键的属性。它是建立关系(表与表之间)的关键连接点。
记忆技巧:外键之所以是“外”的,是因为它属于另一个表,但在当前表中使用它来建立连接。
示例:如果 TEACHER 表中有一个 DeptID(外键),那么这个 DeptID 必须匹配 DEPARTMENT 表中现有的 DeptID(主键)。
3. 数据库设计与规范化技术
为什么要规范化(Normalisation)?
规范化是设计数据库结构的过程,旨在减少数据冗余(重复存储相同数据)并提高数据完整性(确保数据的准确性和一致性)。
如果不进行规范化,你可能会面临:
- 更新异常 (Update Anomalies): 必须在多个地方更改同一信息。(如果课程名称更改,你必须更新所有选课学生的记录)。
- 插入异常 (Insertion Anomalies): 除非同时拥有主键数据,否则无法添加新数据。
- 删除异常 (Deletion Anomalies): 删除一条数据导致丢失其他不相关的数据。
第三范式(3NF)
教学大纲要求你理解第三范式(3NF)以及为什么要对数据库进行规范化。你不需要区分第一、第二和第三范式。
如果一个关系(表)满足特定属性,它就处于 3NF,其中最重要的是消除传递依赖(Transitive Dependencies)。
3NF 的关键属性:
在 3NF 的关系中,每一个非键属性都必须仅依赖于整个主键。 简而言之,任何非键字段都不应依赖于另一个非键字段。
存在问题的示例(未达到 3NF):
表 ORDER(OrderID, CustomerID, CustomerName, ItemPrice)。
在这里,CustomerName 依赖于 CustomerID,而不是直接依赖于 OrderID(主键)。如果客户更改了名字,你必须更新他们下过的所有订单记录。为了解决这个问题,我们将其拆分为两个表:ORDER 和 CUSTOMER。
通过达到 3NF,我们确保了数据库的健壮性、灵活性以及更新的高效性。
4. 结构化查询语言 (SQL)
SQL 是与关系型数据库交互的标准语言。它允许你定义数据结构(DDL)并操作数据(DML)。
数据定义语言 (DDL):定义表
你需要知道如何使用 SQL 定义数据库表,并指定键和数据类型。
需掌握的关键数据类型:
- Integer(整数)和 Real/Float(实数/浮点数)。
- String(字符串/文本)和 Boolean(布尔值,True/False)。
- Date/Time(日期/时间)。
创建表的示例:
CREATE TABLE Products (
ProductID INTEGER PRIMARY KEY,
Name STRING,
Price REAL
);
你还需要知道如何使用单个字段添加简单的外键约束:
CREATE TABLE Orders (
OrderID INTEGER PRIMARY KEY,
CustomerID INTEGER,
FOREIGN KEY (CustomerID) REFERENCES Customers(CustomerID)
);
数据操作语言 (DML):管理数据
你必须熟悉以下基本的 SQL 命令:
1. 检索数据 (SELECT)
用于从数据库中读取数据。
- SELECT [属性] FROM [表] WHERE [条件] ORDER BY [属性]
- 示例:
SELECT Name, Price FROM Products WHERE Price > 100.00 ORDER BY Price DESC;
2. 插入数据 (INSERT)
用于添加新记录(行)。
- INSERT INTO [表] VALUES (值1, 值2, ...);
- 示例:
INSERT INTO Products VALUES (101, 'Laptop', 1200.00);
3. 更新数据 (UPDATE)
用于更改现有记录。务必使用 WHERE,否则你会更新表中的所有记录!
- UPDATE [表] SET [属性] = [新值] WHERE [条件];
- 示例:
UPDATE Products SET Price = 1250.00 WHERE ProductID = 101;
4. 删除数据 (DELETE)
用于删除记录。再次强调,务必使用 WHERE!
- DELETE FROM [表] WHERE [条件];
- 示例:
DELETE FROM Products WHERE ProductID = 101;
SQL 聚合函数
这些函数对一组行进行计算并返回单个汇总值。你通常会将它们与 GROUP BY 一起使用,以对数据子集应用计算。
- COUNT: 返回匹配指定标准的行数。
- SUM: 返回数值列的总和。
- AVG: 计算数值列的平均值。
- MIN: 返回列中的最小值。
- MAX: 返回列中的最大值。
示例: SELECT COUNT(StudentID) FROM Students WHERE Course = 'CS';
配合 GROUP BY 的示例: SELECT Course, AVG(Score) FROM Results GROUP BY Course;
5. 客户-服务器数据库(Client-Server Databases)
在大多数大型系统中,数据库托管在中央服务器上,由许多不同的用户(客户端)访问。这种设置被称为客户-服务器数据库系统。
并发访问(Concurrent Access)
并发访问意味着多个客户端(用户)可以同时尝试访问和修改相同的数据。这虽然提高了效率,但也带来了主要风险:丢失更新问题(Lost Update Problem)。
丢失更新问题
当两个或多个用户几乎在同一时间尝试更新同一记录,导致更新相互干扰时,就会出现这个问题。
步骤示例:
- 客户端 A 读取银行账户余额:$100。 \n
- 客户端 B 读取相同的银行账户余额:$100。
- 客户端 A 计算存款($100 + $50 = $150)并将 $150 写回数据库。
- 客户端 B 计算取款($100 - $20 = $80)并将 $80 写回数据库。
结果: 客户端 A 的 $50 存款丢失了。最终余额为 $80,而本应是 $130。
记录锁(Record Locks)
为了保持数据完整性(确保数据正确),必须使用记录锁来控制并发访问。
记录锁禁止其他用户在一名用户正在处理或修改记录时访问该记录。
工作原理: 当客户端 A 开始编辑银行余额时,系统会对该记录加锁。客户端 B 必须等待客户端 A 提交(保存)其更改并释放锁后,才能访问该记录。
6. 大数据(Big Data)
你知道吗? 我们现在每两天产生的数据量,超过了从人类文明起源到 2003 年的总和!
大数据是一个概括性术语,指那些规模庞大或极其复杂,以至于难以使用传统数据库方法(如我们刚讨论的关系型数据库)进行存储、处理或分析的数据集。
大数据的三个 V (Three Vs)
大数据通常由三个主要特征定义:
- 容量 (Volume): 数据量巨大,无法存放在单个服务器上或使用传统工具处理。
- 速度 (Velocity): 数据往往高速流入(例如股票市场价格、社交媒体推送),需要实时响应(毫秒级到秒级)。
- 多样性 (Variety): 数据形式多样(结构化数据、非结构化文本、视频、传感器读数等)。这种缺乏统一结构的情况使得关系表不再适用。
分布式处理与函数式编程
由于数据量太大,一台服务器无法胜任,因此必须将处理任务分布在多台机器上。
函数式编程 (FP) 语言(你以后可能会学习)常用于处理大数据,因为它们非常擅长编写正确且高效的分布式代码。这是因为 FP 依赖于:
- 不可变数据结构 (Immutable Data Structures): 数据创建后无法更改,从而防止了跨服务器的并发问题。
- 无状态性 (Statelessness): 函数不依赖或改变外部状态,这使得它们很容易在不同的服务器上独立运行。
- 高阶函数 (Map-Reduce): 像 Map-Reduce 这样的技术(将函数映射到所有元素,然后将结果规约为一个单一值)被用于合并来自不同服务器的分布式处理结果。
大数据的数据模型(非关系型)
因为大数据往往缺乏严格的结构,所以需要非关系型模型。
事实模型 (Fact-Based Model)
在这个模型中,每一条信息都被捕获为单一事实。
示例:与其使用包含 (姓名, 年龄, 地址) 的一行数据,不如存储三个独立的事实:(姓名: 张三), (年龄: 30), (地址: 北京)。
图形模式 (Graph Schema: 节点、边、属性)
图形数据库用于表示复杂的关系(如社交网络或推荐系统)。
- 节点 (Node / 实体): 代表个体实体(显示为椭圆形)。
- 边 (Edge / 关系): 连接两个节点的实线,上面标有描述关系的文字(例如“喜欢”、“是朋友”)。
- 属性 (Properties / 属性): 实体的特征(显示为连接到椭圆形的矩形)。
以 Facebook 为例:你是节点。你所在的城市是属性。“是朋友”是连接你与另一个节点的边。