来源:
c:\Users\26947\Desktop\考试\专业课速记\01_数据库与SQL.md用途:分类保存“原文完整迁移”基准,供完整阅读与逐字核对;以下正文保持源文件原样,不压缩、不改写。
数据库与 SQL¶
1. 实际场景:银行转账¶
假设账户 A 给账户 B 转账 1,000 元:
- 从账户 A 扣除 1,000 元。
- 给账户 B 增加 1,000 元。
- 两步都成功后提交;任何一步失败就全部撤销。
这说明数据库概念不是孤立定义,而是用来保证银行交易不出错。
- 原子性:扣款和入账必须一起成功或一起失败,不能只扣款不入账。
- 一致性:转账前后金额关系正确,A 少 1,000,B 多 1,000,总金额不凭空增加或减少。
- 隔离性:多笔转账同时进行时,彼此不能读取不完整的中间状态。
- 持久性:系统显示转账成功后,即使服务重启,交易结果也不能消失。
典型处理逻辑:
中途失败时执行 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。双方互相等待对方释放锁,就卡住了。死锁成立的四个必要条件:
- 互斥
- 请求并保持
- 不可剥夺
- 循环等待
银行场景:转账必须放在同一个事务中,否则可能出现扣款成功但入账失败。
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. 码:候选码与外码(外键)¶
候选码:在一张表里,能唯一确定一条记录,而且已经"精简到不能再删字段"的字段组合。
判断分两步:
- 这个字段或字段组合能否唯一确定一行?
- 是否最小?去掉其中任意一个字段后,都不能再唯一确定一行?
同时满足才是候选码。
示例(账户表):
| 客户号 | 账号 | 客户姓名 | 手机号 |
|---|---|---|---|
| C101 | A001 | 林晓 | 138… |
| C101 | A002 | 林晓 | 138… |
- 假设每个账号全局唯一,则
{账号}是候选码。 {客户号, 账号}也能唯一标识记录,但客户号是多余的(去掉后账号仍唯一),因此不是候选码。
相关概念辨析:
- 超码:能唯一标识一行即可,不要求最小。例:
{账号, 客户姓名}是超码但不是候选码。 - 候选码:最小超码,一个表可能有多个。
- 主码(主键):从候选码中选定的主要标识。
- 主属性:至少属于一个候选码的属性。
- 非主属性:不属于任何候选码的属性。
例:客户表中"客户号"和"身份证号"都能独立唯一标识客户,则二者都是候选码;设计时可选客户号作主键,身份证号作唯一键。
速记:候选码 = 能唯一标识记录的最小字段集;主键 = 选定的候选码。
外码(外键,Foreign Key)¶
定义:外码是本表中引用另一张表主码(或候选码)的字段或字段组合。设 F 是关系 R 中的属性(组),若 F 与关系 S 的主码相对应,则 F 是 R 的外码;R 称为参照关系,S 称为被参照关系。
判断要点:
- 外码是"站在本表角度"对别的表主码的引用,方向是"我引用你"。
- 外码的取值:要么为空(若允许 NULL),要么必须等于被参照表中已存在的主码值——这正是参照完整性。
- 外码在自身表中不要求是候选码;一张表可以有多个外码。
银行例子:
| 表 | 字段 | 角色 |
|---|---|---|
| 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:1 联系:可与任意一端实体合并(在合并端加入另一端的主键作外键);也可独立成表。
- 1:n 联系:合并到 n 端(n 端加入 1 端的主键作外键);也可独立成表(主键取 n 端的主键)。
- m:n 联系:必须独立成关系模式,其主键 = 两端实体主键的组合,联系自身的属性(如份额、数量)也放入该表。
银行例子:
- 客户(1:n)账户:一个客户多个账户 → 账户表加
customer_id外键,不必单独建表。 - 账户(m:n)理财产品:一个账户可买多只产品,一只产品被多个账户持有 → 必须单独建持有表:
考试易错点:
- 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(网点编号, 网点名称, 网点电话)。
判断流程速记¶
- 每个字段不可再分?→ 满足 1NF(原子性)。
- 非主属性完全依赖候选码(没有只依赖复合码一半的)?→ 满足 2NF(消部分依赖)。
- 非主属性直接依赖候选码(没有绕道其他非主属性的)?→ 满足 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)是数据库实施实体完整性的一种约束,要求主键唯一且非空。
- 因此,若题目问“主键属于哪类完整性约束”,答案是:实体完整性;若问“主键是不是一种码”,答案是:主键是从候选码中选定的码。
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 易混点¶
- 主键不是完整性约束类别,但主键约束属于实体完整性。
- 唯一性不等于主键:
UNIQUE列通常允许 NULL(具体行为依数据库而异),主键不允许 NULL 且每张表通常只能定义一个主键。 - 外键不一定唯一:多个交易可以引用同一个客户;外键主要保证“引用对象存在”。
- 外键为 NULL 不等于引用错误:若业务允许空值,NULL 表示暂未建立引用关系;若列声明
NOT NULL,才禁止为空。 - CHECK 约束通常只能直接检查当前行条件;跨行、跨表的复杂规则常需断言、触发器或业务代码。
- 完整性约束与安全控制不同:约束保证数据合法,权限控制保证用户有权操作,二者不能混为一谈。
11.6 参照完整性动作¶
违反参照完整性时的处理(删除/更新被参照记录时):
RESTRICT/NO ACTION:拒绝执行(常见默认行为)。CASCADE:级联删除或更新关联记录。SET NULL:把引用端外键置空(外键列需允许NULL)。
场景例:客户注销时,若仍有账户或交易记录,默认 RESTRICT 会拒绝删除,避免交易记录失去关联。
速记:实体管主键,参照管外键,用户定义管业务;主键是码,主键约束才是约束。
12. 视图(VIEW)¶
定义:视图是基于基表的查询定义的虚表。数据库只存视图的定义(SQL 语句),不存实际数据;查询视图时实时从基表取数。
优点:
- 简化查询:把复杂 JOIN、聚合封装成一个简单的视图名,业务方直接
SELECT * FROM v_customer_balance。 - 安全控制:只暴露部分行、列。柜员视图只含账号、户名、余额,隐藏身份证号、风险评级等敏感字段;不同岗位绑定不同视图,实现"按角色看数据"。
- 逻辑独立性:基表结构变化时修改视图定义,应用程序仍照常查询视图,无需改动。
限制与易考点:
- 视图是虚表,本身不存储数据。
- 含聚合函数、GROUP BY、DISTINCT 或多表 JOIN 的视图不能直接 INSERT/UPDATE/DELETE;只有映射单个基表、直接对应行列子集的简单视图才可更新。
DROP VIEW只删除视图定义,不影响基表数据。
13. 索引(场景:像账户目录,帮助快速定位记录)¶
索引既是逻辑对象,也是物理存储结构¶
逻辑上,索引是数据库中的一种辅助访问对象:用户通过 CREATE INDEX 指定在哪些列上建立索引,查询优化器可以选择利用它加快检索。
物理上,索引会真实存储在磁盘或 SSD 中,通常组织为 B+ 树节点、哈希桶、索引页,以及指向数据记录的键值或指针。因此索引会占用存储空间。
这体现了物理数据独立性:底层改变索引结构或存储方式时,应用通常仍使用相同的 SQL。
场景:没有索引时,查一个账号可能要逐行扫描整张表;有索引时,先通过索引定位,再读取对应记录。
- B+ 树索引像按顺序整理的目录,适合查单个值,也适合范围查询,例如"查询本月交易"。
- 哈希索引像按键直接找位置,适合精确匹配账号,但不适合按日期范围查找。
- 联合索引最左匹配:建了
(customer_id, create_time)索引,按customer_id或customer_id + create_time查询通常能利用它;只按create_time查询则不一定。 - 索引不是越多越好:交易表每新增一个索引,插入和更新时也要维护它,写入会变慢。
- 对索引字段做函数处理,可能让数据库难以直接使用索引。
14. SQL 高频点(场景:统计客户月交易总额)¶
场景:统计每个客户本月交易总额,只看总额超过 10,000 元的客户。
执行顺序理解:
WHERE:先筛出本月交易(分组前过滤行)。GROUP BY:按客户分组。SUM:计算每位客户的交易总额。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)
易错点:
- 自然连接自动匹配同名列——若两表有多个同名列会全部参与比较,易出事故,生产环境慎用
NATURAL JOIN,写显式ON更安全。 - 自然连接属于内连接:无匹配的行被丢弃;要保留无匹配行需用外连接(LEFT/RIGHT JOIN)。
- 笛卡尔积(
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 是等值连接的结果。
🟡 本分册解释为通用计算机知识补充,可能与你老师讲的不完全一致;专业范围以《考试大纲》"金融监管计算机类"部分为准。