第7章
数据库
把数据从程序的附庸,变成全组织共享的资产
本章导航:一条从乱到治的主线
八个部分、四十七页:先看数据管理如何从人工走向数据库系统,再看三级模式与 DBMS,随后学关系模型与 E-R 设计,最后用函数依赖把表一路规范到 3NF。点击任意站点可直接跳转。
导入:数据库管的不是文件,是组织的记忆
📍 只是数据
车辆位置坐标、货物重量、装卸时刻、客户签收记录——一条条原始记录躺在各处:车载终端里、仓库系统里、快递员 PDA 里。它们本身不回答任何问题。
💡 成为信息
把它们统一组织、关联汇总之后才得到:运输时效分析、库存周转率报表、异常预警——能消除不确定性、支撑决策的东西。数据库技术就是这套“从数据到信息”的组织基础设施。
三个基本概念:数据、信息、数据处理
阶段一 · 人工管理:数据依附于程序
🕰️ 时代画像(—1950s 中期)
- 计算机主要用于科学计算,数据量小
- 外存只有纸带、卡片、磁带;没有操作系统、没有数据管理软件
- 数据由各程序自行管理
🧬 结构特征
程序 1 只配数据 1、程序 2 只配数据 2——数据随程序运行而存在,处理结束即不保留。数据不能共享、不能长期保存、无法独立于程序存在,是三阶段中耦合最紧的形态。
阶段二 · 文件系统:能存了,但各存各的
💾 进步(1950s 后期—60s 中期)
磁盘、磁鼓等直接存取设备出现,操作系统日益完善:数据以文件形式长期保存、由文件系统负责读写——相对人工阶段是质变。
🧨 三个老毛病
- 冗余高:文件面向单一应用设计,同一数据在多个文件重复存储
- 共享有限:各应用守着自己的文件
- 独立性差:文件格式一变,程序必须同步修改
🎓 一致性事故现场
教务处、财务处、图书馆各自维护学生信息文件:学生转专业时若三处更新不同步,同一名学生的专业在三个系统里三个样——冗余必然孕育不一致,这是数据库阶段必须解决的头号问题。
阶段三 · 数据库系统:统一管理、组织共享
📅 三个年份
1968 IBM 推出商品化 IMS(层次型先声)· 1969 DBTG 报告提出数据库技术概念与方法 · 1970 起 Codd 发表关系模型论文,奠定关系数据库理论基础。此后数据不再从属于单个应用,而由 DBMS 统一管理、供整个组织共享。
| 维度(习题 2) | 人工管理 | 文件系统 | 数据库系统 |
|---|---|---|---|
| 保存 | 不保留 | 文件长期保存 | 长期、统一组织 |
| 共享 | 无 | 有限 | 多部门多应用共享 |
| 冗余 | — | 高、多文件重复 | 可控 |
| 独立性 | 无,依附程序 | 差,格式变程序变 | 高(二级映像,§7.3) |
| 并发控制 | 无 | 无专门机制 | DBMS 统一控制 |
系统组成:技术、数据、人员与规则的运行体系
🛠️ DBA 数据库管理员
既参与设计,又负责存储结构、权限、完整性约束、备份恢复、性能监测与重构。大型系统中是专业团队;小型系统可由程序员或用户兼任。
👩💻 应用程序员
开发面向最终用户的应用系统:界面与业务逻辑都经 DBMS 访问数据,不直碰文件。
🧑 最终用户
通过应用界面或查询工具使用数据库——他们看到的是第 7.3 节说的“外模式”视图。
主要目标:共享、正确、安全地用数据
🤝 共享与降冗余
不同部门、不同应用访问一致的数据来源;统一建模让同一事实只存一处,重复存储与重复维护随之减少。
🧱 独立性
应用开发与底层存储细节解耦:数据结构变化时,应用程序受影响最小(机制在 §7.3)。
✅ 一致与完整
数据符合业务规则与语义约束(机制在 §7.7);多用户并发访问时结果正确、状态一致。
🛟 恢复能力
异常或断电后能恢复到正确状态——事务与日志是背后的工具。
🔐 安全性
身份认证、授权与审计防非法访问与滥用。
🎯 一句话
提高数据资源的组织效率与使用价值——其余五项都是为这一句服务的手段。
先行概念:模式是型,实例是值
🧬 模式(Schema)
对全体数据逻辑结构与特征的描述,只谈“型”、不谈具体值。如学生关系模式:学生(学号, 姓名, 性别, 出生日期, 专业号)——它相对稳定。
📸 实例(Instance)
模式在某一时刻的具体值:如 2026 级全体学生的实际记录集合。它随增删改不断变化——模式是相框,实例是照片。
三级模式:用户视图、全局蓝图、存储实现
二级映像:两层翻译换来两种独立性
🧱 物理独立性(概念/内映像保证)
改存储不惊动逻辑:加索引、换文件组织方式——只要概念模式不变,应用程序无需修改。好比换仓库货架,商品清单不变。
🧩 逻辑独立性(外/概念映像保证)
改逻辑不惊动用户视图:全局结构适度调整(如加新表新字段),只要外模式保持稳定,面向用户的程序可以不变。好比超市扩品类,常购清单不变。
部署结构:集中四形态与分布式
| 集中式结构 | 处理分工 | 典型问题 |
|---|---|---|
| 单用户结构 | 应用、DBMS、数据库同在一机,单人使用 | 多机之间不能直接共享 |
| 主机/终端(主从式) | 主机完成全部处理,终端只管输入输出 | 主机成瓶颈、可靠性要求高 |
| 客户机/服务器 C/S | 客户端担界面与部分逻辑,服务器担 DBMS | 客户端升级维护成本高 |
| 浏览器/服务器 B/S | 客户端只用浏览器,逻辑集中在应用服务器 | 客户端最省心,服务端负担重(C/S 的特例) |
DBMS 五大功能:定义、操纵、控制、维护、通信
内部组成与一次请求的旅程
四类部件
数据模型:结构、操作、约束三件套
🧱 数据结构
数据如何组织:有哪些对象、对象间什么联系。
🕹️ 数据操作
能在数据上做哪些事:查询、插入、修改、删除等基本操作。
⚖️ 完整性约束
数据必须遵守的规则——§7.7 的完整主题就是它。
| 抽象层次(习题 5) | 面向对象 | 主要任务 | 常见形式 |
|---|---|---|---|
| 概念模型 | 用户与业务人员 | 描述实体、属性与联系 | E-R 模型 |
| 逻辑数据模型 | DBMS 与设计人员 | 以形式化结构表示数据及联系 | 层次、网状、关系模型 |
| 物理数据模型 | 系统实现与运维人员 | 描述存储记录、索引、访问路径 | 存储结构定义与配置参数 |
前辈模型:树与图的局限
🌲 层次模型
以树形结构组织数据:每个子结点通常只有一个双亲,天生适合一对多(院系→专业→学生)。结构清晰、访问效率高;死穴是表达不了多对多——学生选课这种关系只能靠冗余或虚拟结点硬凑。IMS 就是它的代表。
🕸️ 网状模型
允许一个结点有多个双亲、结点间多种联系,比层次模型贴近现实。代价:结构复杂、导航性强——程序员要亲自在网中“找路”,开发难度大。DBTG 方案是其代表。
关系模型:一切都是二维表
Codd 1970 年提出,以集合论与谓词逻辑为根基:实体与联系都用二维表表示。优势是概念单一、结构清晰、数据独立性强、可用统一查询语言操作。数学上:各属性的域 D₁…Dₙ 做笛卡儿积得到所有可能元组,关系就是其中实际存在的有限子集。
| 术语(习题 6) | 含义 | 术语 | 含义 |
|---|---|---|---|
| 关系 | 一张二维表 | 元组 | 表中的一行记录 |
| 属性 | 表中的一列 | 域 | 属性的取值范围,如性别的域为 {男, 女} |
键的体系:标识与引用的骨架
🎯 候选键
能唯一标识元组且不含多余属性的属性(组):唯一性+最小性,两条缺一不可。一个关系可有多个候选键。
👑 主键
从候选键中选定一个作为正式标识。只能有一个;主键属性不能为空(§7.7 实体完整性)。
🔗 外键
引用其他关系主键的属性(组)——联系在关系模型中的化身(§7.7 参照完整性)。
设计五原则:不是画表,是做权衡
🎯 语义准确
表、字段、联系真实反映业务对象及其关系——设计的及格线。
🧱 结构清晰
层次分明、命名统一、主外键明确。
♻️ 冗余受控
避免不必要的重复存储(工具是 §7.8 规范化)。
⚖️ 约束完整
关键业务规则尽量由数据库约束表达,而不是只靠应用代码自觉。
🌱 易于扩展
新增业务时不必推倒重来。
🚫 两个极端
不是表越少越好,也不是拆得越细越好——在语义完整、可维护、执行效率之间找平衡。
六个阶段:从业务到运行的流水线
以第一阶段为例:需求分析先于一切表结构
任务不是急着画表,而是弄清:系统管理哪些对象、处理哪些业务、保存哪些数据、支持哪些查询报表、必须遵守哪些规则。高校选课系统的需求至少要识别学生、教师、课程、班级、院系、选课记录、成绩记录等对象,并明确规则:学生可选多门课、课程可被多人选;成绩必须依附于选课记录存在;学分必须为正值——这些规则后面分别变成联系类型与完整性约束。
E-R 模型:矩形、椭圆、菱形画世界
| 元素 | 图形 | 含义 |
|---|---|---|
| 实体 | 矩形 ▭ | 可区分并需描述的现实对象:学生、供应商、仓库、零件 |
| 属性 | 椭圆 ⬭ | 实体或联系所具有的特征:学号、姓名、地址、数量、单价 |
| 联系 | 菱形 ◇ | 实体之间的业务关联:“学生选修课程”“供应商供应零件”“仓库存放货物” |
联系类型
1:1 一个班级一个班长 · 1:n 一个专业多个学生 · m:n 学生与课程互选 · 自联系 员工上下级 · 多元联系 供应商向项目供零件。判断联系两端“一个实例最多牵连对方多少个”(基数分析),类型就定了——它直接决定下一页的转换规则。
概念设计的手艺:认实体、定属性
🔍 实体识别三判据
- 有独立存在意义、有若干可描述属性、需长期保存
- 先认核心实体,再考虑辅助实体与联系实体
- 物流库存例:仓库、货物、供应商、订单是核心实体;“入库记录”既可看作业务事件,也可建模为联系实体——取决于要不要保存它的时间、数量、经办人等细节
🏷️ 属性的分类与取舍
- 简单 vs 复合:地址=省+市+区+详细地址(复合)
- 单值 vs 多值:一个学生多个电话号码即多值
- 存储 vs 派生:年龄可由出生日期推导,宜作派生属性、不落库
- 共同要求:语义清楚、粒度适中、可维护
一张 E-R 图:学生选修课程
学生 ▭m —— ◇ 选修 ◇ —— n课程 ▭
⬭ 课程号 · ⬭ 课程名
🔎 怎么读这张图
两个实体各带属性椭圆;中间菱形“选修”是联系,两端标注 m 与 n:一个学生可选多门课、一门课可被多个学生选——m:n 联系。
⭐ 最关键的一笔
联系本身也有属性:成绩挂在“选修”菱形上——它既不是学生固有的(换门课就换成绩),也不是课程固有的(换个学生就换成绩),只属于“某生选了某课”这件事。
转换规则:四条走天下
动手转:高校课程管理系统的逻辑设计
需求已定:实体有专业、院系、教师、学生、课程;联系为专业—学生 1:n、院系—教师 1:n、教师—课程 n:1(一课一师)、学生—课程 m:n(选修带成绩与选课时间)。分三步把它转成关系模式。
先从实体开始——每个实体先成为一张表。
案例定稿:六张表,与一个变体
教师(工号, 姓名, 职称, 院系号→院系) 学生(学号, 姓名, 性别, 入学年份, 专业号→专业)
课程(课程号, 课程名, 学分, 开课学期, 工号→教师) 选课(学号, 课程号, 成绩, 选课时间)
🔀 变体:联合授课
若允许多位教师合授一门课且教师可教多门课,教师—课程升级为 m:n:课程表须摘掉工号,另立授课(课程号, 工号, 授课时间, 授课学时)表,联合主键、双外键;授课时间与学时是联系的属性。若同师同课可跨学期重复,学期还要进主键——业务规则一变,模式立刻跟着变,这就是设计的本质。
初学者两大常见病:报表思维与属性错位
🗞️ 病一:用报表思维代替建模
照着“学生选课一览表”的样子建表:一张表里同时塞学生姓名、课程名、教师名、教室和成绩——看起来贴合展示,实则多类实体混杂一表,违背关系建模原则,更新异常与冗余在 §7.8 等着它。报表是数据的“用法”,不是数据的“存法”。
🎯 病二:混淆实体属性与联系属性
把成绩塞进学生表或课程表——它明明是“选修”这一联系的属性(第 24 页)。判据一问:这属性的值随谁变?换门课变、换学生也变,那就只属于“选课”这件事。
完整性:数据的正确、有效、一致
正确性看类型与格式是否合法;有效性看取值是否在业务允许范围;一致性看表达同一事实的多个数据是否相互协调。关系模型从三个层面守这三条:
1️⃣ 实体完整性
保证每个元组可被唯一标识——盯主键。
2️⃣ 参照完整性
保证关系之间的引用合法——盯外键。
3️⃣ 用户定义完整性
保证具体业务规则得到满足——盯业务语义。
实体完整性:主键非空,联合主键全员非空
🔑 单主键
学生(学号, 姓名, 性别, 专业号)
学号是唯一标识的依据:每个学生元组必须有非空学号。学号为空的记录无法被准确区分,等于“查无此人”,系统直接拒绝。
🔐 联合主键
选课(学号, 课程号, 成绩)
主键由两属性组成时,任何一个主属性都不能空:只有学号+课程号共同存在,才能唯一确定“某生的一次选课”。缺一,这条记录就指认不了。
参照完整性:引用必须找得到对象
定义与规则
设关系 R 的属性(组)F 与另一关系 S 的主键相对应,则 F 是 R 的外键;R 叫参照关系,S 叫被参照关系。规则只有一条:R 中每个元组在 F 上的取值,要么为空,要么等于 S 中某个真实存在的主键值。外键的双重身份:既表达实体间的联系,又把引用值锁在被参照表的实际名单里。
⚠️ 一个前提
“外键可为空”以它不参与主键为前提。若外键同时是复合主键的成员,实体完整性要求其非空——选课表的学号、课程号同为外键与主键成员,只能取真实存在的学生与课程,没有空值选项。
两个案例,与自引用外键
🎓 学生—专业
专业(专业号, 专业名称)只有 CS、IS、LOG 三行
学生(学号, 姓名, 专业号)
学生的专业号只能是 CS / IS / LOG 或空(尚未分专业);填“XX01”即违反参照完整性,当场被拒。
📝 选课三表
选课表中的学号必须来自学生表、课程号必须来自课程表——否则就会出现“不存在的学生在上不存在的课”这种语义事故。
🪞 自引用外键
外键也可以指向本表:员工(工号, 姓名, 上级工号) 中“上级工号”引用本表工号——为空表示最高管理者,否则必须是已存在的员工。第 22 页 E-R 的“自联系”在此落地。
用户定义完整性:普适规则之外的业务规矩
📚 教务与商品例
- 课程学分必须为正整数;学生成绩在 0—100 之间
- 产品价格大于 0;折后价不得高于原价
- 身份证号在系统内唯一
📋 课程表约束集
课程(课程号, 课程名, 学分)
- 课程号非空且唯一;课程名非空
- 学分取值 1—6;部分课程名全校不得重复
⚖️ 硬约束 ≠ 预警规则
仓储例:库存(仓库号, 货物号, 数量, 安全库存)中“数量非负、安全库存非负”是硬约束,违反即拒绝写入;而“数量低于安全库存”只是业务预警,触发提醒但不拦截保存——把预警做成硬约束,系统会被正常业务堵死。
习题 9 落点:三类完整性的 SQL 化身
| 约束机制 | 守哪类完整性 | 示例语义 |
|---|---|---|
| PRIMARY KEY | 实体完整性 | 学号为主键:唯一且非空自动生效 |
| NOT NULL | 实体/用户定义 | 课程名不能为空 |
| FOREIGN KEY … REFERENCES | 参照完整性 | 学生.专业号 引用 专业.专业号 |
| UNIQUE | 用户定义 | 身份证号全系统唯一 |
| CHECK | 用户定义 | CHECK(学分 BETWEEN 1 AND 6)、CHECK(成绩 BETWEEN 0 AND 100) |
| DEFAULT | 用户定义(辅助) | 状态字段缺省取“在读” |
一张大表的四宗罪
🚫 插入异常
缺了某些字段值,本应存在的信息插不进去:新专业尚无学生,专业信息无处登记。
🗑️ 删除异常
删一条记录时,连带丢失本应保留的信息:删掉某专业最后一名学生,专业本身也从库里消失了。
✏️ 更新异常
同一事实存了多处,改时漏改一处即不一致:改了 99 行的电话号码,漏了 1 行。
♻️ 冗余过高
同一数据反复出现,既浪费存储,又给前面三种异常供弹药。
函数依赖:X 定,Y 必定
定义:关系模式 R(U)中,若任意两个元组只要在 X 上取值相同,在 Y 上取值必然也相同,则称 Y 函数依赖于 X,记作 X → Y——X 能唯一确定 Y。
🎓 直觉例
学号 → 姓名, 专业号, 入学年份
同一个学号,必然对应同一个学生、同一个专业、同一年入学——身份证号→姓名、订单号→下单时间,都是同一种“决定”关系。
⚠️ 读定义要抠字眼
它说的是任意两个元组与必然:不是“碰巧当前数据里没冲突”,而是由业务语义保证永远成立。函数依赖来自语义,不来自样本——这是全 §7.8 最重要的纪律。
部分函数依赖:半个键就能定
若 Y 依赖于组合键 X,却也只依赖于 X 的某一部分(真子集),则 Y 对 X 是部分函数依赖;若不依赖任何真子集,才是完全函数依赖。它只出现在联合主键的场合——单属性主键永远无此问题。
学号 → 学生姓名 (姓名只认学号,与课程号无关)
课程号 → 课程名 (课程名只认课程号)
(学号, 课程号)→ 成绩 (成绩必须双键齐定 —— 完全依赖)
传递函数依赖:隔着一层决定
学号 → 专业号 专业号 → 专业名称 ∴ 学号 → 专业名称(传递)
🧬 定义内核
X → Y、Y → Z,且 Y 不是 X 的子集、Z 不是 Y 的子集、不存在 Y → X 时,Z 对 X 是传递函数依赖。直白说:主键不直接管它,它听命于另一个非主属性。
♻️ 危害
专业名称随每个学生重复存储:物流专业 300 名学生,“物流管理”四字存 300 遍;专业改名就得改 300 处——更新异常的标准剧本。它是 3NF 的靶心(第 42 页),也是习题 11 的原型。
1NF:每格只放一个值
定义:每个属性值都是不可再分的原子值。三种典型违规:合并单元格;一格塞多个值;一格混合多段含义(如“省-市-区-详细地址”又需分别处理)。
❌ 违规的表
| 学号 | 姓名 | 课程号 |
|---|---|---|
| 1022 | 张三 | DB01、OS02、NW03 |
| 4123 | 李四 | DB01、AI05 |
✅ 拆行后的 1NF
| 学号 | 姓名 | 课程号 |
|---|---|---|
| 1022 | 张三 | DB01 |
| 1022 | 张三 | OS02 |
| 1022 | 张三 | NW03 |
| 4123 | 李四 | DB01 |
2NF:非主属性须完全依赖于键
定义:属于 1NF,且所有非主属性都完全函数依赖于每个候选键。病灶:联合主键里藏部分依赖。药方:把“只靠半个键”的属性连同其决定方拆成独立表。
拆:学生(学号, 姓名, 导师办公室) + 选课(学号, 课程号)
案例:成绩登记表为什么是三张表的合影
学号 → 学生姓名 · 课程号 → 课程名, 学分 · (学号, 课程号)→ 成绩
3NF:非主属性不许隔代听命
定义:属于 2NF,且每个非主属性都不传递函数依赖于任何候选键。药方:把“由非主属性决定的属性”连同决定方独立成表。
❌ 分解前
学生(学号, 姓名, 专业号, 专业名称)
学号 → 专业号 → 专业名称
✅ 分解后
学生(学号, 姓名, 专业号)
专业(专业号, 专业名称)
巩固案例:教师信息藏在课程表里
课程号 → 课程名, 教师号 · 教师号 → 教师姓名, 教师办公室
教材 §7.8.6 全程:一张表 → 四张表
动画:《规范化分解实例》(2 分 01 秒)
阶梯总结:够用在 3NF,例外要有意识
| 范式 | 解决的核心问题 | 典型方法 |
|---|---|---|
| 1NF | 消除重复组、保证属性原子性 | 每个字段只保存一个值 |
| 2NF | 消除非主属性对联合主键的部分依赖 | 把部分依赖属性拆到独立表 |
| 3NF | 消除非主属性对主键的传递依赖 | 把由非主属性决定的属性继续拆分 |
一句话带走本章:统一管理、分层隔离、按依赖拆表
📌 本章带走的六件事
- 数据管理三阶段:依附程序 → 各存文件 → DBMS 统一管理与共享
- 三级模式+二级映像:外看局部、概念看全局、内看存储,换来物理与逻辑双独立
- 关系模型:一切皆二维表;候选键讲唯一与最小,主键选一个,外键表联系
- 设计六阶段:需求→E-R→关系模式→物理→实施→维护;m:n 联系必须独立成表
- 完整性三类:主键非空、外键有据、业务规则用约束写进库里
- 规范化阶梯:1NF 原子化、2NF 去部分依赖、3NF 去传递依赖,多数系统到 3NF 够用
✍️ 课后思考
- 习题 8:学生-课程局部 E-R 图+关系模式——转换器里练过一遍同款
- 习题 10:成绩登记表的依赖分析与逐步分解——第 41、44 页是方法原型
- 习题 12:你的课程设计里想保留哪处冗余?说清是权衡还是欠账
下一章预告:第 8 章 数据仓库 —— 当数据攒到要回答“为什么”时,联机分析接棒。