第一部分函数依赖与属性闭包1. 基本属性闭包计算题目R(A, B, C, D, E), F { A→BC, CD→E, B→D, E→A }。设 X {A, B}求 X⁺。答案与解析初始化X⁺ {A, B}。步骤1由 A→BC将 C 加入 X⁺。X⁺ {A, B, C}。步骤2由 B→D将 D 加入 X⁺。X⁺ {A, B, C, D}。步骤3由 CD→E现在 X⁺ 包含 C 和 D满足左部将 E 加入 X⁺。X⁺ {A, B, C, D, E}。步骤4由 E→AA 已在 X⁺ 中无新属性加入。结论X⁺ {A, B, C, D, E}。因为 X⁺ 包含了 R 的所有属性所以 {A, B} 是一个超键。2. 判断候选键题目R(S, T, U, V, W), F { S→TU, U→V, VW→S }。a) 求 {S}⁺。b) 求 {V, W}⁺。c) 判断 {S} 和 {V, W} 是否为候选键。答案与解析a) {S}⁺初始化{S}。由 S→TU加入 T, U。{S, T, U}。由 U→V加入 V。{S, T, U, V}。现在有 V但 VW→S 的左部需要 WW 不在当前闭包中无法触发。{S}⁺ {S, T, U, V}。未包含所有属性故 {S} 不是超键。b) {V, W}⁺初始化{V, W}。由 VW→S加入 S。{S, V, W}。由 S→TU加入 T, U。{S, T, U, V, W}。{V, W}⁺ {S, T, U, V, W}。包含了 R 的所有属性故 {V, W} 是超键。c) 判断{S}其闭包未包含所有属性不是候选键。{V, W}其闭包包含所有属性。需要检查其真子集 {V} 和 {W} 是否为超键。显然单个 V 或 W 的闭包不可能包含 S因此 {V, W} 的任何真子集都不是超键。所以{V, W} 是一个候选键。3. 闭包与逻辑推导题目R(A, B, C), F { A→B, B→C }。证明 A→C。答案与解析已知 A→B (给定)。已知 B→C (给定)。根据 Armstrong 公理的传递律若 A→B 且 B→C则 A→C。因此函数依赖 A→C 成立。第二部分键超键、候选键、主键、外键4. 键的概念辨析a) 学生表 (学号, 姓名, 院系)超键任何能唯一标识元组的属性集如(学号)、(学号, 姓名)、(学号, 院系)、(学号, 姓名, 院系)。甚至(姓名, 院系)如果确定唯一也可以是超键。候选键不含多余属性的超键。通常(学号)就是一个候选键。如果身份证号也存在于表中且唯一非空那么(学号)和(身份证号)都是候选键。主键从候选键中选出的一个用于管理和引用。通常选择学号作为主键。b) 选课表 (学号, 课程号, 成绩) 的候选键单一属性无法唯一标识一条选课记录一个学生选多门课一门课有多个学生选。属性组合(学号, 课程号)可以唯一标识一条记录且其任何真子集学号或课程号都不能唯一标识。因此(学号, 课程号)是候选键通常也是主键。c) 选课表中的外键及其引用外键学号和课程号。引用学号引用学生表 (Student)的主键学号。课程号引用课程表 (Course)的主键课程号。5. 键与函数依赖题目R(P, Q, R, S, T), F { PQ→R, Q→S, S→T }。a) 找所有候选键思路找出只出现在函数依赖左部或未出现在任何依赖中的属性它们通常是候选键的必要部分。P 只出现在PQ→R的左部未出现在右部。Q 出现在左部但也出现在Q→S的右部不Q→S中 Q 在左部。先看整体P 和 Q 都未出现在任何函数依赖的右部。因此{P, Q} 必须在候选键中。计算 {P, Q}⁺初始化 {P, Q}。由 PQ→R加入 R。{P, Q, R}。由 Q→S加入 S。{P, Q, R, S}。由 S→T加入 T。{P, Q, R, S, T}。{P, Q}⁺ 包含所有属性且其真子集 {P} 和 {Q} 的闭包显然不包含所有属性。因此{P, Q} 是唯一的候选键。b) 判断最高满足的范式候选键是 {P, Q}。检查 2NF是否存在部分函数依赖观察非主属性 R, S, T。R 完全依赖于候选键 {P, Q} (PQ→R)OK。S 依赖于 Q (Q→S)而 Q 是候选键的真子集。这属于部分函数依赖违反了 2NF。结论由于存在部分函数依赖该关系模式最高只满足1NF。第三部分综合应用题6. 规范化与闭包a) 函数依赖集 F项目ID → 项目名称 一个项目有唯一ID和名称项目ID → 负责人ID 一个项目由一位负责人负责负责人ID → 负责人姓名, 负责人部门 一位负责人有唯一的ID、姓名和部门因此F {项目ID → 项目名称, 负责人ID,负责人ID → 负责人姓名, 负责人部门}b) 候选键根据语义和函数依赖项目ID可以决定所有其他属性。计算 {项目ID}⁺根据 F可推出 {项目ID, 项目名称, 负责人ID, 负责人姓名, 负责人部门}包含所有属性。且项目ID是单属性没有真子集。因此候选键是 {项目ID}。c) 数据冗余与更新异常存在。因为负责人姓名和负责人部门依赖于负责人ID而不是直接依赖于主键项目ID。冗余同一位负责人负责多个项目时其姓名和部门信息会在多条项目中重复存储。更新异常修改某负责人的部门时需要更新他负责的所有项目记录容易遗漏。插入异常无法单独录入一位尚未负责项目的负责人信息。删除异常删除某个项目后如果该负责人只负责这一个项目其信息也会丢失。d) 分解为 3NF/BCNF这是一个典型的传递依赖案例。可以分解为两个符合 BCNF也符合 3NF的关系项目表 (Project):(项目ID, 项目名称, 负责人ID)。主键项目ID。外键负责人ID引用负责人表.负责人ID。负责人表 (Manager):(负责人ID, 负责人姓名, 负责人部门)。主键负责人ID。7. 闭包的应用等价判断思路判断 F⁺ G⁺等价于证明 F 覆盖 G 且 G 覆盖 F。通常的方法是检查 G 中的每个函数依赖是否在 F⁺ 中以及 F 中的每个函数依赖是否在 G⁺ 中。关键步骤检查 G 中的依赖是否在 F⁺ 中A→CD计算 {A} 关于 F 的闭包。{A}⁺由 A→C得 {A, C}。由 AC→D左部 AC 已在闭包中加入 D。得 {A, C, D}。因此 A→CD 成立。E→AH计算 {E} 关于 F 的闭包。{E}⁺由 E→AD得 {E, A, D}。由 A→C (已证 A→C 在 F⁺ 中)加入 C。得 {E, A, D, C}。由 E→H加入 H。得 {E, A, D, C, H}。因此 E→AH 成立。结论G ⊆ F⁺。检查 F 中的依赖是否在 G⁺ 中A→C由于 G 中有 A→CD根据分解规则A→C 显然在 G⁺ 中。AC→D由于 G 中有 A→CD根据增广律AC→CD 在 G⁺ 中再根据分解律AC→D 在 G⁺ 中。E→AD由于 G 中有 E→AH且 A→CD 在 G⁺ 中可推导出 E→AD具体步骤略类似闭包计算。E→H直接包含在 E→AH 中根据分解律可得。结论F ⊆ G⁺。最终判断因为 F 覆盖 G 且 G 覆盖 F所以F 与 G 等价。第四部分键值对数据库NoSQL8. 概念理解与传统关系型数据库相比键值对数据库的主要特点数据模型简单只有“键”和“值”两个部分。值通常是未解释的二进制大对象或简单数据结构如字符串、列表、集合不强制要求固定的模式Schema-Free。查询方式单一只能通过唯一的键进行精确查询不支持像 SQL 那样的复杂查询如连接、范围查询、聚合等除非特定实现支持额外索引。高性能与高扩展性模型简单带来了极高的读写速度尤其适合基于内存的操作。通常通过分布式架构实现水平扩展容易分片。适用场景缓存、会话存储、排行榜、计数器、消息队列、存储配置项等需要极快读写和简单数据模型的场景。9. 设计题a) Key 和 Value 设计Key:session:{session_id}(例如session:abc123)。为什么使用前缀便于管理session_id本身是全局唯一标识符适合作为键。Value: 一个序列化后的数据结构如 JSON、MessagePack包含user_id、login_time、last_activity等字段。例如{user_id: 1001, login_time: 2023-10-27T08:00:00Z, last_activity: 2023-10-27T09:30:00Z}。为什么将相关信息封装在一起一次读写即可获取全部会话数据。b) 按 user_id 查询的问题与改进问题在纯键值模型中只能通过session_id这个键来查询。要找到某个user_id的所有会话需要遍历所有键这在数据量大时效率极低不可行。改进思路使用二级索引创建一个新的键值对集合以user_id为键的一部分。例如Key:user_sessions:{user_id}:{session_id}Value: 可以为空或存储少量元数据。这样要查询user_id1001的所有会话可以使用KEYS user_sessions:1001:*或更好的方式如 Redis 的SCAN命令或使用SET存储 session_id 列表。使用 Set 或 Sorted Set 数据结构如果存储支持为每个user_id维护一个Set存储其所有的session_id。Key:user:{user_id}:sessionsValue: 一个 Set包含如abc123,def456等session_id。查询时直接获取这个 Set 即可。选择支持二级索引的键值数据库一些现代键值或文档数据库原生支持二级索引。