表设计与范式:从 1NF 到反范式权衡
0. 元信息
- 主题路径:
docs/topics/db-and-sql/subtopics/schema-design-and-normalization/README.md - 主分类:计算机基础
- 辅助分类:Web 与后端
- 适合对象:完成父主题前置阶段的开发者
- 建议周期:1~3 周,每周 8~12 小时
- 前置知识:relational-model-and-sql
- 最终目标:能从函数依赖推导无损分解,并用查询基准证明反范式
1. 学习路线
需求不变量 → 函数依赖 → 候选键 → 范式分解 → 查询模式 → 反范式与索引
2. 阶段周数分配
本子主题按实验推进,不固定周数。每完成一个概念就留下 SQL、输入数据、输出和解释。
3. 九阶段表(精简)
| 阶段 | 核心知识 | 实践产出 | 学会标准 |
|---|---|---|---|
| 1. 建模 | entity、key、functional dependency、1NF、2NF、3NF、BCNF、denormalization | 概念图与最小 schema | 能说清每个概念解决什么问题 |
| 2. 实验 | PostgreSQL 行为、错误与边界 | 可重跑 SQL | 能预测正常和异常结果 |
| 3. 对照 | MySQL/SQLite 差异 | 差异表 | 能区分标准语义和实现行为 |
| 4. 工程 | 版本、数据规模、可观测输出 | 技术报告 | 能用证据解释选择 |
4. 第一周任务
精简版不固定 Day 1~7。执行约定是 PostgreSQL 16+、psql -v ON_ERROR_STOP=1、脚本可在空库重复运行。
5. 阶段通用验收
以 §3 的可观察标准和 §9.4 题目为验收。
6. 最终验收
独立完成一份最小实验、三组数据、一份解释和一次 PostgreSQL/MySQL 行为对照。
7. 综合项目
并入父主题“小型电商数据库”,本子主题负责 关系模式设计 的设计、实验与报告。
本主题贡献
- 在父主题
db-and-sql的综合项目「小型电商数据库」中,本主题(表设计与范式)负责 关系模式设计:从业务不变量推导出函数依赖(FD),做候选键求解与无损分解,平衡 1NF / 2NF / 3NF / BCNF 与反范式后的查询性能。 - 把 §1 路线「需求不变量 → 函数依赖 → 候选键 → 范式分解 → 查询模式 → 反范式与索引」落到订单域(orders / order_items / shipments / addresses)4 张表与 1 张反范式视图:先写 FD 集合与候选键推导,再用
CREATE TABLE落地 3NF 起步,证明无损分解后JOIN不引入伪元组;对读多写少的「订单详情」做反范式物化视图 + 覆盖索引。 - 与 db-and-sql 其它子主题对接:把 schema 输出当作 index-and-query-plan 的最小 schema 与 seed 源;给 transaction-and-isolation 提供唯一约束 / 外键定义用于复现 409 Conflict 与 FK 级联;把建表脚本交给 relational-model-and-sql 跑 SQL 正确性断言。
交付物清单:
schema/fd.md:≥ 5 条核心 FD 集合(如{order_id} → user_id, created_at),附候选键推导与闭包计算;schema/decomp.md:≥ 2 个从 3NF 到 BCNF 的无损分解演示,附R1 NATURAL JOIN R2前后行数 / 行集合对比(含 NULL 行),并标注依赖保持情况;schema/denorm.md:订单详情 1 张反范式物化视图(CREATE MATERIALIZED VIEW或触发器维护),附pg_stat_statements/EXPLAIN BUFFERS上 P95 延迟改前 / 改后数字(≥ 30% 降幅);schema/ddl.sql:完整 DDL(≥ 8 张表),约束 + 注释 + 反范式视图 + 维护触发器(可选),在 PG 16+ 与 MySQL 8.4 各跑一次。
验收标准:
- BCNF 分解演示中,
R1 NATURAL JOIN R2行数 ≡ 原关系行数(无损),不含原关系没有的元组; - 反范式视图在 EXPLAIN BUFFERS 上 P95 延迟下降 ≥ 30%,且写路径增加 SQL ≤ 2 条;
- DDL 在 PostgreSQL 16+ / MySQL 8.4 各
pg_dump/mysqldumpround-trip 成功。
8. 推荐资料
见 §9.3。先用 PostgreSQL 官方文档和课程实验,书用于补理论。
9. 学习资料汇聚(v0.3 自包含)
9.1 背景与动机
规范化减少更新异常,物理设计服务真实查询。真实系统还要处理数据规模、失败和并发。我们用 PostgreSQL 实验观察语义,再用 MySQL 核对实现差异。
9.2 概念地图
flowchart LR
A[需求与数据] --> B[关系与约束]
B --> C[SQL]
C --> D[Planner / Transaction]
I[Index / Statistics] --> D
D --> E[执行与并发]
E --> F[结果 / 延迟 / 锁等待]
F --> G[验证与修改]
G --> C
核心概念:entity、key、functional dependency、1NF、2NF、3NF、BCNF、denormalization。图中从业务不变量出发,经 SQL、计划或事务到可观察结果,再用相同数据验证修改。
9.3 基础知识讲解
9.3.1 经典论文
| 资料 | 贡献 | 读法 |
|---|---|---|
| Codd, A Relational Model of Data for Large Shared Data Banks | 关系模型与 data independence | 读定义与例子 |
| Selinger et al., Access Path Selection in a Relational DBMS | 成本优化器 | 对照 EXPLAIN |
| Gray et al., Granularity of Locks and Degrees of Consistency | 锁与一致性 | 画锁兼容和事务 schedule |
9.3.2 经典书籍
| 书 | 侧重 | 用法 |
|---|---|---|
| Silberschatz, Korth & Sudarshan, Database System Concepts | 全景教材 | 读本子主题对应章 |
| C. J. Date, Database Design and Relational Theory | 关系理论 | 核对键、依赖与范式 |
| Joe Celko, SQL for Smarties | 高级 SQL | 复做集合式查询 |
9.3.3 优秀博客与文档
| 资料 | 特点 | 用法 |
|---|---|---|
| PostgreSQL Documentation | 权威行为说明 | 查目标版本 |
| Use The Index, Luke | Markus Winand 的索引与 SQL 案例 | 复现实验 |
| MySQL Reference Manual | MySQL/InnoDB 对照 | 核对方言和默认值 |
9.3.4 核心人物
| 人物 | 影响 | 材料 |
|---|---|---|
| Edgar F. Codd | 关系模型 | 1970 论文 |
| C. J. Date | 关系理论与教学 | 关系理论著作 |
| Andy Pavlo | 数据库系统教学与研究 | CMU 15-445 课程 |
9.3.5 开发与学习方法
| 方法 | 动作 | 何时用 |
|---|---|---|
| Query-first | 先写期望结果和业务不变量 | 正确性设计 |
| Single-variable experiment | 每次只改一处 SQL、索引或事务设置 | 因果验证 |
| Differential test | PostgreSQL 与 MySQL 对跑 | 识别标准与实现差异 |
课程补充:CMU 15-445 适合数据库实现,Berkeley CS186 适合系统课程与实验。Andy Pavlo 的课堂讲解用于连接论文、实现与计划输出。
9.4 经典问题与经典案例
| 问题 | 为什么重要 | 最简答案 |
|---|---|---|
| 候选键和主键差在哪 | 防止概念或工程误判 | 候选键都最小唯一,主键是选中的一个 |
| 2NF 消除什么 | 防止概念或工程误判 | 非主属性对候选键的部分依赖 |
| 3NF 与 BCNF 差在哪 | 防止概念或工程误判 | BCNF 要求每个决定因素都是超键 |
| 分解怎样算无损 | 防止概念或工程误判 | 连接后不产生伪元组 |
| 反范式何时合理 | 防止概念或工程误判 | 已测得读收益且能维护一致性时 |
| 索引属于逻辑设计吗 | 防止概念或工程误判 | 通常属于物理设计,不改变关系语义 |
9.5 学习难点
概念难点
| 难点 | 为什么会卡 | 突破路径 |
|---|---|---|
| 抽象语义与产品实现 | 教材定义和默认行为容易混在一起 | 先写标准概念,再查目标版本文档 |
| 多个概念同时影响结果 | 单看 SQL 文本不够 | 画数据、计划或事务时间线 |
| NULL、重复或并发边界 | 正常样例会隐藏问题 | 强制加入边界数据和双会话实验 |
思维难点
| 难点 | 为什么会卡 | 突破路径 |
|---|---|---|
| 集合与状态推理 | 容易按应用循环想问题 | 先写结果关系或状态不变量 |
| 从相关性到因果 | 改动后变快不代表改动有效 | 固定数据与环境,每次只改一项 |
| 正确性与性能并看 | 快结果可能是错结果 | 先断言结果,再比较计划和耗时 |
工程难点
| 难点 | 为什么会卡 | 突破路径 |
|---|---|---|
| 数据形状不真实 | 小样本计划没有代表性 | 测规模、选择性、倾斜和 NULL |
| 版本差异 | 默认值与语法会变 | 保存 SELECT version() 和引用日期 |
| 实验不可重跑 | 手工操作丢步骤 | DDL、seed、query、cleanup 全写脚本 |
9.6 技术标准与接口
9.6.1 Entity
| 名称 | 主流版本 | 发布组织 | 状态 | 许可证 / 可访问性 |
|---|---|---|---|---|
| PostgreSQL | 16~18 | PGDG | 活跃 | PostgreSQL License;文档公开 |
| MySQL | 8.4 LTS / 9.x | Oracle | 活跃 | GPLv2 Community / 商业版 |
| SQLite | 3.x | SQLite Consortium | 活跃 | Public Domain |
| Oracle Database | 19c / 23ai | Oracle | 活跃 | 商业许可 |
| SQL Server | 2022 / 2025 | Microsoft | 活跃 | 商业/Developer |
| SQL | ISO/IEC 9075 | ISO/IEC JTC 1/SC 32 | 持续修订 | 正文通常收费 |
9.6.2 Scope
本子主题处理 关系模式设计。SQL 标准描述通用语义,产品文档描述 planner、storage、locking 等实现。不要把 PostgreSQL 扩展当成所有数据库的共同保证。
9.6.3 Structure
必须掌握的接口:DDL/DML、约束、SELECT/JOIN、事务控制、EXPLAIN (ANALYZE, BUFFERS)、system catalog 与统计视图。具体重点是:entity、key、functional dependency、1NF、2NF、3NF、BCNF、denormalization。
9.6.4 Ecosystem
PostgreSQL 是主实验环境。MySQL 用于 InnoDB 和 optimizer 对照。SQLite 适合单文件实验。Oracle 与 SQL Server 用来了解企业产品的方言、执行计划和并发差异。JDBC、ODBC、DB-API 是常见客户端接口。
9.6.5 Depth Tiers
| 层级 | 能力 | 可观察标准 |
|---|---|---|
| L0 | 知道存在 | 能说出核心名词 |
| L1 | 看得懂示例 | 能读 SQL、计划或事务脚本 |
| L2 | 能正确调用 | 能完成正常与边界实验 |
| L3 | 能解释与排错 | 能用结果、计划、锁或日志解释问题并验证修改 |
| L4 | 能设计与扩展 | 能修改优化器、存储或并发控制实现 |
本计划要求达到 L3。
9.6.6 Source
- PostgreSQL 官方文档:引用快照 2026-07-30。
- MySQL Reference Manual:引用快照 2026-07-30。
- ISO SQL 标准条目:引用快照 2026-07-30。
10. 常见误区
- 用单个正常样例证明理解;
- 混淆逻辑结果与物理执行顺序;
- 忽略 NULL 与三值逻辑;
- 把数据库默认行为当业务规范;
- 不保存版本、DDL 和种子数据;
- 看到索引就断言查询会更快;
- 只看平均耗时,不看计划和数据分布;
- 在生产直接试破坏性 SQL;
- 长事务里做网络调用;
- 跨数据库迁移时只检查语法;
- 用 ORM 隐藏生成 SQL 后不再检查;
- 修改后不重跑相同正确性断言。
11. 所有知识点分类(统一规则)
- 编程语言
- 数据结构与算法
- 计算机基础
- 工程技术
- Web 与后端
- 前端与客户端
- 数据与人工智能
- 项目与职业能力
- 安全与可靠性
本计划归属:计算机基础 主 + Web 与后端 辅。