跳转至

来源:c:\Users\26947\Desktop\考试\专业课速记\01_数据库与SQL.md 用途:分类保存“原文完整迁移”基准,供完整阅读与逐字核对;以下正文保持源文件原样,不压缩、不改写。


数据库与 SQL

1. 实际场景:银行转账

假设账户 A 给账户 B 转账 1,000 元:

  1. 从账户 A 扣除 1,000 元。
  2. 给账户 B 增加 1,000 元。
  3. 两步都成功后提交;任何一步失败就全部撤销。

这说明数据库概念不是孤立定义,而是用来保证银行交易不出错。

  • 原子性:扣款和入账必须一起成功或一起失败,不能只扣款不入账。
  • 一致性:转账前后金额关系正确,A 少 1,000,B 多 1,000,总金额不凭空增加或减少。
  • 隔离性:多笔转账同时进行时,彼此不能读取不完整的中间状态。
  • 持久性:系统显示转账成功后,即使服务重启,交易结果也不能消失。

典型处理逻辑:

BEGIN;

UPDATE account
SET balance = balance - 1000
WHERE account_id = 'A001';

UPDATE account
SET balance = balance + 1000
WHERE account_id = 'A002';

COMMIT;

中途失败时执行 ROLLBACK,保证扣款和入账不会只成功一半。

2. 事务 ACID

  • Atomicity,原子性:事务要么全部成功,要么全部失败。
  • Consistency,一致性:事务执行前后,数据库从一个合法状态变成另一个合法状态。
  • Isolation,隔离性:多个事务并发执行时,彼此不能看到不该看到的中间状态。
  • Durability,持久性:提交后的修改永久保存。

3. 四种隔离级别(场景:并发读写产生错账)

场景:账户 A 有 1,000 元,同时有两个转账请求各转 800 元。如果两个请求都先读到"余额 1,000",再各自扣款,就可能超额转出。数据库通过锁和隔离机制控制这类并发问题。

隔离级别 脏读 不可重复读 幻读
Read Uncommitted 可能 可能 可能
Read Committed 避免 可能 可能
Repeatable Read 避免 避免 一般仍可能
Serializable 避免 避免 避免

三种并发异常的场景理解:

  • 脏读:读到另一笔尚未提交的修改。对方最后回滚了,你却依据这笔"临时数据"做了决策。
  • 不可重复读:同一事务两次读取账户余额,期间别的事务修改并提交了,两次结果不同。
  • 幻读:同一事务两次查询"余额低于 100 元的账户",两次查到的账户数量不同,通常是中间有记录被新增或修改到查询范围内。

强弱顺序:Read Uncommitted 最弱 → Read Committed → Repeatable Read → Serializable 最强。隔离越强,一致性保护越强,但并发性能通常越受影响。

4. 锁与死锁(场景:给账户记录加"使用权限")

  • 共享锁 S 锁像"允许多人同时查看":多个事务可以同时读。
  • 排他锁 X 锁像"正在修改,请暂时别动":写入时阻止其他冲突读写。

转账扣款常见做法是先锁住账户记录,再检查余额和扣款,避免两个事务同时根据旧余额做决定。

  • 两阶段锁协议:事务先加锁,释放锁后不能再加锁。

死锁场景:事务 1 锁住账户 A、等待账户 B;事务 2 锁住账户 B、等待账户 A。双方互相等待对方释放锁,就卡住了。死锁成立的四个必要条件:

  1. 互斥
  2. 请求并保持
  3. 不可剥夺
  4. 循环等待

银行场景:转账必须放在同一个事务中,否则可能出现扣款成功但入账失败。

5. 事务日志(Redo / Undo 与 WAL)

事务日志是数据库自动维护的"操作流水账",记录事务对数据的修改操作,是实现原子性和持久性的底层机制。

为什么只记修改:故障恢复时,数据库只需重做(redo)已提交的修改、撤销(undo)未提交的修改,保证不丢数据、不留半成品;查询不改动数据,恢复时无需重放。

两类日志:

日志 记录内容 用途 保障
重做日志 Redo Log "做了什么修改"(修改后的值) 宕机重启后重放已提交事务 持久性
回滚日志 Undo Log "如何撤销修改"(修改前的值/反向操作) 事务回滚、MVCC 读旧版本 原子性

先写日志原则(WAL,Write-Ahead Logging):修改数据前必须先把对应日志写入并落盘,再修改数据页。若先改数据后写日志,日志尚未落盘就宕机,数据库就无法知道要恢复什么。

检查点(Checkpoint):定期把内存中的脏页批量刷盘,并推进日志位置,缩短宕机后的恢复时间。

银行场景:转账执行到扣款后、入账前断电。重启时数据库根据日志自动处理——已提交的事务重做(redo),未提交的事务回滚(undo),资金既不会丢,也不会停在"只扣款未入账"的中间状态。

查询操作有没有类似的日志?(易混点)

SELECT 不写入事务日志——事务日志为故障恢复和回滚服务,只关心"数据被改成了什么样"。但查询行为并非无迹可寻,数据库另有几类日志,用途完全不同:

日志 记录内容 主要用途 银行场景
审计日志 谁在何时执行了什么 SQL(含 SELECT) 合规、追责、防内部泄密 监管要求"查客户信息必留痕",员工偷看客户资料可追溯
通用查询日志 所有 SQL 语句(默认关闭) 调试 开销大,生产环境慎用
慢查询日志 执行时间超过阈值的查询 性能调优 定位"查账户列表特别慢"之类的 SQL

速记:事务日志为恢复而生(只记修改),审计日志为合规而生(查询也留痕)。两类日志互不替代:前者保数据不丢不错,后者保行为可追溯。

6. 数据管理三阶段

人工管理阶段 → 文件系统阶段 → 数据库系统阶段

一句话速记:人工管理"人管数据";文件系统"程序管文件";数据库系统"数据库管理系统统一管数据"。

人工管理阶段(纸质账本时代):

  • 数据由人工记录和管理,与业务程序无明确分离。
  • 容易重复、丢失和出错;查询修改效率低;多人难以共享。
  • 例:客户改手机号需在多个账本分别修改,漏改则不一致。

文件系统阶段(customer.txt、account.txt 等分散文件):

  • 数据以文件保存,由各应用程序分别管理,效率提高但:
  • 数据冗余:客户信息同时存在储蓄、信用卡、贷款系统,改一处漏其他。
  • 数据不一致:同一客户不同系统中手机号不同。
  • 程序与数据耦合强:文件格式一变,所有读它的程序都可能要改。

数据库系统阶段(DBMS 统一管理):

  • 数据集中统一管理,共享性强、冗余可控、一致性好。
  • 支持并发访问、事务、故障恢复、权限控制,可用 SQL 灵活查询。
  • 数据独立性(重要特征):
  • 物理独立性:修改存储方式不影响应用程序。
  • 逻辑独立性:修改逻辑结构不影响应用程序。
对比维度 人工管理 文件系统 数据库系统
数据载体 纸质账本 计算机文件 数据库
数据共享 很弱 较弱 强
数据冗余 高 较高 可控制
数据独立性 没有 较低 较高
并发控制 基本没有 较弱 完善
故障恢复 依靠人工 较弱 日志、备份、恢复

核心考点:文件系统阶段的主要问题是数据冗余、不一致、共享困难、程序与数据耦合;数据库系统阶段的核心优势是共享性高、独立性高、冗余小、统一管理控制。

7. 三级模式与两级映像

数据库体系结构 = 三级模式 + 两级映像,这是"数据独立性"的理论基础。

三级模式(从外到内):

模式 又称 含义 银行例子
外模式 用户视图、子模式 单个用户/应用看到的数据结构 柜员只看到账号、户名、余额
模式 逻辑模式、概念模式 数据库整体逻辑结构(全库的表和联系) 客户表、账户表、交易表及其联系
内模式 存储模式、物理模式 数据实际存储方式(文件组织、索引、压缩) 客户表按 B+ 树聚簇存储

一个数据库只有一个模式、一个内模式,但可以有多个外模式。

两级映像:

  • 外模式/模式映像:模式改变(如加字段、改表结构)时,只需修改映像,外模式保持不变,应用程序不用改 → 保证逻辑数据独立性。
  • 模式/内模式映像:内模式改变(如换存储结构、加索引)时,只需修改映像,模式保持不变 → 保证物理数据独立性。

场景例:客户表增加"身份证号"字段(模式变化),柜员视图仍只暴露账号和余额(外模式不变),柜员端程序无需修改——这就是外模式/模式映像在"吸收变化"。

速记:映像负责吸收变化,改动被限制在 DBMS 内部,不波及应用程序。

8. 码:候选码与外码(外键)

候选码:在一张表里,能唯一确定一条记录,而且已经"精简到不能再删字段"的字段组合。

判断分两步:

  1. 这个字段或字段组合能否唯一确定一行?
  2. 是否最小?去掉其中任意一个字段后,都不能再唯一确定一行?

同时满足才是候选码。

示例(账户表):

客户号 账号 客户姓名 手机号
C101 A001 林晓 138…
C101 A002 林晓 138…
  • 假设每个账号全局唯一,则 {账号} 是候选码。
  • {客户号, 账号} 也能唯一标识记录,但客户号是多余的(去掉后账号仍唯一),因此不是候选码。

相关概念辨析:

  • 超码:能唯一标识一行即可,不要求最小。例:{账号, 客户姓名} 是超码但不是候选码。
  • 候选码:最小超码,一个表可能有多个。
  • 主码(主键):从候选码中选定的主要标识。
  • 主属性:至少属于一个候选码的属性。
  • 非主属性:不属于任何候选码的属性。

例:客户表中"客户号"和"身份证号"都能独立唯一标识客户,则二者都是候选码;设计时可选客户号作主键,身份证号作唯一键。

速记:候选码 = 能唯一标识记录的最小字段集;主键 = 选定的候选码。

外码(外键,Foreign Key)

定义:外码是本表中引用另一张表主码(或候选码)的字段或字段组合。设 F 是关系 R 中的属性(组),若 F 与关系 S 的主码相对应,则 F 是 R 的外码;R 称为参照关系,S 称为被参照关系。

判断要点:

  1. 外码是"站在本表角度"对别的表主码的引用,方向是"我引用你"。
  2. 外码的取值:要么为空(若允许 NULL),要么必须等于被参照表中已存在的主码值——这正是参照完整性。
  3. 外码在自身表中不要求是候选码;一张表可以有多个外码。

银行例子:

表 字段 角色
customer(客户表) customer_id 主码
account(账户表) account_id 主码
account(账户表) customer_id 外码,引用 customer.customer_id
  • account 是参照关系,customer 是被参照关系。
  • 账户表的 customer_id 必须指向真实存在的客户,不能出现"未注册客户名下的账户"。
  • 客户注销(删除被参照记录)时若账户仍在,将违反参照完整性,数据库默认 RESTRICT 拒绝(详见第 11 节完整性约束)。

外码可以是自身主码的一部分:m:n 联系转换出的持有表 holding(account_id, product_id, share),主码是 (account_id, product_id),其中 account_id 是账户表的外码、product_id 是产品表的外码——组合主码的每个成员同时是外码,这在多对多联系表中很常见。

码家族对比(高频选择题):

概念 一句话 关键特征
超码 能唯一标识一行即可 唯一,不要求最小
候选码 最小的超码 唯一 + 最小
主码 从候选码中选定的标识 唯一 + 非空(实体完整性)
外码 引用别的表的主码 值为空或存在于被参照表(参照完整性)

速记:主码标识"自己这一行",外码指向"别人表的行";主码管唯一,外码管引用。

9. E-R 模型转换关系模式

E-R 模型三要素:实体(矩形)、属性(椭圆)、联系(菱形),联系两端标注 1:1、1:n、m:n。

转换规则:

  1. 每个实体 → 一个关系模式;实体的属性 → 关系的属性;实体的码 → 关系的主键。
  2. 1:1 联系:可与任意一端实体合并(在合并端加入另一端的主键作外键);也可独立成表。
  3. 1:n 联系:合并到 n 端(n 端加入 1 端的主键作外键);也可独立成表(主键取 n 端的主键)。
  4. m:n 联系:必须独立成关系模式,其主键 = 两端实体主键的组合,联系自身的属性(如份额、数量)也放入该表。

银行例子:

  • 客户(1:n)账户:一个客户多个账户 → 账户表加 customer_id 外键,不必单独建表。
  • 账户(m:n)理财产品:一个账户可买多只产品,一只产品被多个账户持有 → 必须单独建持有表:
holding(account_id, product_id, share)
主键:(account_id, product_id)

考试易错点:

  • m:n 联系不能并入任何一端实体,必须单独建表,组合主键。
  • 1:n 联系应并入 n 端(多端),不要错并入 1 端。
  • 联系本身的属性(如"持有份额")跟随联系走,不留在实体表里。

10. 范式(场景:客户信息重复、更新不一致)

场景:一张大表每笔交易都重复保存客户姓名、手机号、账户号。客户换手机号时要改很多行,漏改一行就出现同一客户有多个手机号。

规范化做法是把不同实体拆开:

  • 客户表:客户编号、姓名、手机号
  • 账户表:账号、客户编号、余额
  • 交易表:交易编号、转出账号、转入账号、金额、时间

定义与判断(需先明确候选码和函数依赖):

  • 1NF:字段不可再分,保证原子性。
  • 2NF:满足 1NF,且非主属性完全依赖于主键(消除部分函数依赖:非主属性只依赖复合候选码的一部分)。
  • 3NF:满足 2NF,且不存在非主属性对主键的传递依赖(非主属性经由另一个非主属性依赖候选码)。

1NF 案例:字段不可再分

反例:

客户号 姓名 联系方式
C101 林晓 手机:138…, 邮箱:lin@x.com

"联系方式"一列塞进了手机和邮箱两个信息,无法直接按手机号查询或建索引 → 违反 1NF。

1NF 修正:拆成 phone、email 两列。判断口诀:每个格子只装一个值。

2NF 案例:消除部分函数依赖

储蓄业务表 deposit(客户号, 账号, 客户姓名, 余额, 开户网点),复合主码 = (客户号, 账号):

客户号 账号 客户姓名 余额 开户网点
C101 A001 林晓 5000 网点1
C101 A002 林晓 3000 网点2
C102 A003 周芸 8000 网点1

依赖分析:

  • 客户姓名只依赖客户号(复合主码的一半)→ 部分依赖。
  • 余额、开户网点只依赖账号(复合主码的另一半)→ 部分依赖。

带来的异常:

  • 插入异常:新客户尚未开户,姓名无处保存。
  • 删除异常:C102 销掉唯一业务后姓名丢失。
  • 更新异常:林晓改名要改两行,漏改即不一致。

2NF 修正:按"谁依赖谁"拆表——客户表(客户号, 姓名)、账户表(账号, 余额, 开户网点)、业务表(客户号, 账号)。

3NF 案例:消除传递依赖

账户表问题版 account(账号, 余额, 网点编号, 网点名称, 网点电话),主码 = 账号:

账号 余额 网点编号 网点名称 网点电话
A001 5000 B01 朝阳支行 010-…
A002 3000 B02 海淀支行 010-…
A003 8000 B01 朝阳支行 010-…

依赖分析:网点名称、网点电话依赖网点编号,而网点编号依赖账号 → 网点名称、网点电话传递依赖账号。

带来的异常:朝阳支行换电话,要更新该网点下所有账户的行,漏改即不一致。

3NF 修正:account(账号, 余额, 网点编号) + branch(网点编号, 网点名称, 网点电话)。

判断流程速记

  1. 每个字段不可再分?→ 满足 1NF(原子性)。
  2. 非主属性完全依赖候选码(没有只依赖复合码一半的)?→ 满足 2NF(消部分依赖)。
  3. 非主属性直接依赖候选码(没有绕道其他非主属性的)?→ 满足 3NF(消传递依赖)。

一句话口诀:1NF 装一个值,2NF 别只靠半个码,3NF 别绕道。注意 2NF 的部分依赖只出现在复合主码场景——单属性主码的表自动满足 2NF。

  • 范式越高,数据冗余通常越低,但查询连接可能变多。
  • 反规范化:在读性能确实重要时,有控制地保存冗余数据,换取更快查询。

11. 完整性约束

11.1 定义与作用

完整性约束(Integrity Constraint):数据库中用于规定数据必须满足的正确性、有效性和一致性规则。数据库管理系统会在插入、修改、删除数据时自动检查这些规则;若违反约束,通常拒绝操作,防止“脏数据”进入数据库。

银行场景:账户余额不能为负、账户号不能重复、交易记录不能指向不存在的客户,这些都是完整性约束要保证的数据规则。

11.2 三类经典完整性约束

类型 管什么 规则 银行例子
实体完整性 主键 主键值唯一且非空,每行都能被唯一识别 账户表 account_id 不能重复、不能为空
参照完整性 外键 外键值必须为空(允许 NULL 时),或引用被参照表中已存在的候选码/主码 交易表的 customer_id 必须真实存在于客户表
用户定义完整性 具体业务规则 由业务需求定义,如取值范围、格式、默认值、唯一性等 balance >= 0;交易金额 > 0;手机号格式合法

11.3 “主键不属于完整性约束吗?”

要区分主键和主键约束:

  • 主键(Primary Key)本身是关系模型中的一种码,用于唯一标识一行记录,不是“约束类别”名称。
  • 主键约束(PRIMARY KEY constraint)是数据库实施实体完整性的一种约束,要求主键唯一且非空。
  • 因此,若题目问“主键属于哪类完整性约束”,答案是:实体完整性;若问“主键是不是一种码”,答案是:主键是从候选码中选定的码。
1
2
3
4
CREATE TABLE account (
    account_id VARCHAR(20) PRIMARY KEY, -- 同时体现主键定义和实体完整性约束
    balance DECIMAL(18, 2) CHECK (balance >= 0)
);

11.4 还有哪些完整性约束?

考试教材通常重点考“三类经典约束”,但在 SQL 实现中还会看到以下具体约束。它们不是与三类并列的新大类,通常归入用户定义完整性或作为实现手段:

SQL 约束 作用 常见归类 示例
PRIMARY KEY 唯一标识记录,非空且唯一 实体完整性 account_id PRIMARY KEY
FOREIGN KEY 保证表间引用有效 参照完整性 customer_id REFERENCES customer(customer_id)
UNIQUE 限制列或列组合不能重复 用户定义完整性 身份证号、手机号唯一
NOT NULL 不允许缺失值 用户定义完整性/域约束 客户姓名不能为空
CHECK 限制取值范围或业务条件 用户定义完整性/域约束 amount > 0
DEFAULT 未提供值时自动填入默认值 用户定义完整性 账户状态默认“正常”

从数据库理论看,有些教材还会把以下内容单独强调:

  • 域完整性(Domain Integrity):属性值必须来自规定的合法域,例如金额必须是数值、交易金额大于 0、状态只能取“正常/冻结/注销”。不少教材把它归入用户定义完整性。
  • 断言(Assertion):对跨表、全局业务条件进行约束,例如“所有账户余额之和不能小于 0”。这是 SQL 标准中的概念,但实际数据库产品支持情况和考试要求可能不同。
  • 语义完整性/业务完整性:由业务规则表达,例如未成年人不能开通某类产品、已注销账户不能发起交易,通常通过 CHECK、触发器、存储过程或应用程序实现。

注意:权限控制、审计日志、事务隔离性主要解决“谁能访问、行为能否追溯、并发是否互相干扰”,不属于完整性约束本身。

11.5 易混点

  1. 主键不是完整性约束类别,但主键约束属于实体完整性。
  2. 唯一性不等于主键:UNIQUE 列通常允许 NULL(具体行为依数据库而异),主键不允许 NULL 且每张表通常只能定义一个主键。
  3. 外键不一定唯一:多个交易可以引用同一个客户;外键主要保证“引用对象存在”。
  4. 外键为 NULL 不等于引用错误:若业务允许空值,NULL 表示暂未建立引用关系;若列声明 NOT NULL,才禁止为空。
  5. CHECK 约束通常只能直接检查当前行条件;跨行、跨表的复杂规则常需断言、触发器或业务代码。
  6. 完整性约束与安全控制不同:约束保证数据合法,权限控制保证用户有权操作,二者不能混为一谈。

11.6 参照完整性动作

违反参照完整性时的处理(删除/更新被参照记录时):

  • RESTRICT / NO ACTION:拒绝执行(常见默认行为)。
  • CASCADE:级联删除或更新关联记录。
  • SET NULL:把引用端外键置空(外键列需允许 NULL)。

场景例:客户注销时,若仍有账户或交易记录,默认 RESTRICT 会拒绝删除,避免交易记录失去关联。

速记:实体管主键,参照管外键,用户定义管业务;主键是码,主键约束才是约束。

12. 视图(VIEW)

定义:视图是基于基表的查询定义的虚表。数据库只存视图的定义(SQL 语句),不存实际数据;查询视图时实时从基表取数。

优点:

  1. 简化查询:把复杂 JOIN、聚合封装成一个简单的视图名,业务方直接 SELECT * FROM v_customer_balance。
  2. 安全控制:只暴露部分行、列。柜员视图只含账号、户名、余额,隐藏身份证号、风险评级等敏感字段;不同岗位绑定不同视图,实现"按角色看数据"。
  3. 逻辑独立性:基表结构变化时修改视图定义,应用程序仍照常查询视图,无需改动。

限制与易考点:

  • 视图是虚表,本身不存储数据。
  • 含聚合函数、GROUP BY、DISTINCT 或多表 JOIN 的视图不能直接 INSERT/UPDATE/DELETE;只有映射单个基表、直接对应行列子集的简单视图才可更新。
  • DROP VIEW 只删除视图定义,不影响基表数据。
1
2
3
4
-- 柜员视图:只暴露必要字段
CREATE VIEW v_teller_account AS
SELECT account_id, customer_name, balance
FROM account;

13. 索引(场景:像账户目录,帮助快速定位记录)

索引既是逻辑对象,也是物理存储结构

逻辑上,索引是数据库中的一种辅助访问对象:用户通过 CREATE INDEX 指定在哪些列上建立索引,查询优化器可以选择利用它加快检索。

物理上,索引会真实存储在磁盘或 SSD 中,通常组织为 B+ 树节点、哈希桶、索引页,以及指向数据记录的键值或指针。因此索引会占用存储空间。

1
2
3
逻辑层面:CREATE INDEX idx_account_customer ON account(customer_id)
物理层面:数据库实际维护 B+ 树/哈希结构和索引页
应用层面:应用只写查询 SQL,不必知道索引如何存储

这体现了物理数据独立性:底层改变索引结构或存储方式时,应用通常仍使用相同的 SQL。

场景:没有索引时,查一个账号可能要逐行扫描整张表;有索引时,先通过索引定位,再读取对应记录。

  • B+ 树索引像按顺序整理的目录,适合查单个值,也适合范围查询,例如"查询本月交易"。
  • 哈希索引像按键直接找位置,适合精确匹配账号,但不适合按日期范围查找。
  • 联合索引最左匹配:建了 (customer_id, create_time) 索引,按 customer_id 或 customer_id + create_time 查询通常能利用它;只按 create_time 查询则不一定。
  • 索引不是越多越好:交易表每新增一个索引,插入和更新时也要维护它,写入会变慢。
  • 对索引字段做函数处理,可能让数据库难以直接使用索引。
1
2
3
4
5
6
-- 可能导致索引失效
WHERE YEAR(create_time) = 2026

-- 通常更适合使用索引
WHERE create_time >= '2026-01-01'
  AND create_time < '2027-01-01'

14. SQL 高频点(场景:统计客户月交易总额)

场景:统计每个客户本月交易总额,只看总额超过 10,000 元的客户。

1
2
3
4
5
6
SELECT customer_id, SUM(amount) AS total_amount
FROM transactions
WHERE create_time >= '2026-10-01'
  AND create_time < '2026-11-01'
GROUP BY customer_id
HAVING SUM(amount) > 10000;

执行顺序理解:

  1. WHERE:先筛出本月交易(分组前过滤行)。
  2. GROUP BY:按客户分组。
  3. SUM:计算每位客户的交易总额。
  4. HAVING:筛选汇总后总额超过 10,000 的客户(分组后过滤组)。

速记:WHERE 筛行,HAVING 筛组。 WHERE 不能直接使用聚合结果,聚合条件放在 HAVING。

其他易考点:

  • COUNT(*) 统计行数。
  • COUNT(phone) 不统计 phone 为 NULL 的行。
  • INNER JOIN:只保留两表能匹配上的记录。
  • LEFT JOIN:保留左表全部记录;右表没有匹配时,右表字段为 NULL。

连接运算辨析:等值连接与自然连接

这两个是关系代数(关系运算)的概念,与 SQL 语法一一呼应:SELECT ↔ 投影 π,WHERE ↔ 选择 σ,JOIN ↔ 连接,CROSS JOIN ↔ 笛卡尔积。

连接的定义:从两个关系的笛卡尔积中选取满足条件的元组。按条件分类:

  • θ 连接:满足任意比较条件(>、<、= 等)的一般连接。
  • 等值连接(Equi-Join):θ 为 = 的连接,按指定列的值相等来连接。连接列不要求同名,结果保留两表全部列——连接列会出现两次。
  • 自然连接(Natural Join):特殊的等值连接——在所有同名列上自动做相等比较,并去掉重复的连接列,结果中每个同名列只出现一次。
维度 等值连接 自然连接
连接条件 显式指定(任意列相等) 所有同名列自动相等
列名要求 不要求同名 必须同名
连接列在结果中 出现两次 只出现一次
SQL 写法 JOIN ... ON c.id = a.id NATURAL JOIN

银行例子:customer(customer_id, name) 与 account(account_id, customer_id, balance)

1
2
3
4
5
6
7
-- 等值连接:customer_id 出现两次
SELECT * FROM customer c
JOIN account a ON c.customer_id = a.customer_id;

-- 自然连接:在同名列 customer_id 上连接,该列只出现一次
SELECT * FROM customer
NATURAL JOIN account;

易错点:

  1. 自然连接自动匹配同名列——若两表有多个同名列会全部参与比较,易出事故,生产环境慎用 NATURAL JOIN,写显式 ON 更安全。
  2. 自然连接属于内连接:无匹配的行被丢弃;要保留无匹配行需用外连接(LEFT/RIGHT JOIN)。
  3. 笛卡尔积(CROSS JOIN)是无连接条件的运算,行数 = 两表行数相乘,业务上通常是事故。

15. 场景自测题

题 1:银行转账时,账户 A 扣款成功后,给账户 B 入账失败。正确处理方式是什么?

  • A. 保留扣款,稍后再处理
  • B. 回滚本次事务,撤销扣款
  • C. 忽略入账失败
  • D. 只记录错误日志

正确答案:B。这是事务原子性:扣款与入账必须作为一个整体成功或失败。

题 2:设计"账户-理财产品"表,一个账户可买多只产品、一只产品可被多个账户持有,应如何建表?

  • A. 在账户表加 product_id 字段
  • B. 在产品表加 account_id 字段
  • C. 单独建持有表,主键为 (account_id, product_id)
  • D. 不需要记录持有关系

正确答案:C。m:n 联系必须独立成关系模式,组合主键;A、B 都无法表达多对多。

题 3:银行系统把客户表拆分存储结构后,柜员端程序无需修改,这体现了哪一级映像保证的哪种独立性?

正确答案:模式/内模式映像,保证物理数据独立性。若修改的是表逻辑结构(如加字段)而外模式不变,则是外模式/模式映像,保证逻辑数据独立性。

题 4:转账事务提交后服务器立即断电,重启后该笔转账数据完好。最直接的原因是什么?

  • A. 数据页在提交前已全部刷盘
  • B. 重做日志在提交时已先落盘,重启后据此重放
  • C. 回滚日志记录了撤销操作
  • D. 通用查询日志保存了该 SQL

正确答案:B。WAL 要求日志先于数据落盘,redo log 保证持久性。A 不可靠——脏页通常延后刷盘;C 的 undo 用于回滚未提交事务;D 与故障恢复无关。

题 5:customer(customer_id, name) 与 account(account_id, customer_id, balance) 执行自然连接后,结果表的属性列是什么?

  • A. customer_id, name, account_id, customer_id, balance
  • B. customer_id, name, account_id, balance
  • C. name, account_id, balance
  • D. customer_id, name, balance

正确答案:B。自然连接去掉重复连接列,customer_id 只出现一次;A 是等值连接的结果。


🟡 本分册解释为通用计算机知识补充,可能与你老师讲的不完全一致;专业范围以《考试大纲》"金融监管计算机类"部分为准。