关系模型与 SQL:从 SELECT 到 JOIN
0. 元信息
- 主题路径:
docs/topics/db-and-sql/subtopics/relational-model-and-sql/README.md - 主分类:计算机基础
- 辅助分类:Web 与后端
- 适合对象:完成父主题前置阶段的开发者
- 建议周期:1~3 周,每周 8~12 小时
- 前置知识:Linux 命令行与 PostgreSQL 基础环境
- 最终目标:能为给定结果写出正确 SQL,并解释 bag semantics、NULL 与 JOIN 基数
1. 学习路线
关系定义 → SQL 表达式 → JOIN → 聚合 → 窗口函数
2. 阶段周数分配
本子主题按实验推进,不固定周数。每完成一个概念就留下 SQL、输入数据、输出和解释。
3. 九阶段表(精简)
| 阶段 | 核心知识 | 实践产出 | 学会标准 |
|---|---|---|---|
| 1. 建模 | relation、tuple、attribute、key、NULL、JOIN、aggregation、window | 概念图与最小 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. 综合项目
并入父主题“小型电商数据库”,本子主题负责 SQL 查询正确性 的设计、实验与报告。
本主题贡献
- 在父主题
db-and-sql的综合项目「小型电商数据库」中,本主题(关系模型与 SQL)负责 SQL 查询正确性:把 relation / tuple / attribute / key 落到 5 张核心表(users / products / orders / order_items / inventory)的 schema 上,并写出 bag semantics、NULL 三值逻辑、JOIN 基数与窗口函数边界全部正确的查询。 - 把 §1 路线「关系定义 → SQL 表达式 → JOIN → 聚合 → 窗口函数」落成 40+ 条可执行 SQL:用 INNER / LEFT / FULL / CROSS / SELF 区分基数差异;用 WHERE 与 HAVING 分清聚合前/后;用
RANK() / LAG() / NTILE() / SUM() OVER跑排行榜与累计指标。 - 与 db-and-sql 其它子主题对接:把 DDL + seed + SQL + cleanup 全脚本化(
psql -v ON_ERROR_STOP=1可在空库重跑)作为 index-and-query-plan 的最小 schema 与基准输入;把同一套 SQL 在 RC / RR / Serializable 下复测并交给 transaction-and-isolation 出隔离异常矩阵。
交付物清单:
sql/01_schema.sql:5 张核心表 DDL,约束覆盖 PK / UK / FK / CHECK,建索引 ≥ 8 条,附SELECT version()输出;sql/02_select_joins.sql:≥ 25 条 SELECT 含 JOIN 的用例,覆盖 INNER / LEFT / CROSS / SELF 与 WHERE / HAVING,含 bag 与 NULL 边界用例(NOT IN (NULL)、count(*)vscount(col)、WHERE col = NULL);sql/03_window.sql:≥ 8 条窗口函数用例(ROW_NUMBER / RANK / DENSE_RANK / LAG / LEAD / NTILE / SUM() OVER / AVG() OVER)+ 边界用例(PARTITION BY单分组、frame 子句);reports/pg_vs_mysql.md:≥ 3 条 SQL 在 PostgreSQL 16+ 与 MySQL 8.4 下的差异(如INSERT ... ON CONFLICTvsINSERT IGNORE、FILTER (WHERE …)vs 反连接、GROUP BY隐式列、字符序与 UTF8 默认 collation)。
验收标准:
- 全部脚本在空 PostgreSQL 与空 MySQL 各跑一次成功(
ON_ERROR_STOP=1,失败即停),且每次 reset 跑结果相同; - 每条 SQL 输出(含 NULL 与重复行)与
expected/*.txt完全一致,无遗漏行; - 报告至少 3 个差异点,每条差异点附两边的 SQL 与执行结果(含
EXPLAINcost)。
8. 推荐资料
见 §9.3。先用 PostgreSQL 官方文档和课程实验,书用于补理论。
9. 学习资料汇聚(v0.3 自包含)
9.1 背景与动机
Codd 关系模型、SQL 与关系代数之间的差异。真实系统还要处理数据规模、失败和并发。我们用 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
核心概念:relation、tuple、attribute、key、NULL、JOIN、aggregation、window。图中从业务不变量出发,经 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 经典问题与经典案例
| 问题 | 为什么重要 | 最简答案 |
|---|---|---|
| 为什么 SQL 不是纯关系代数 | 防止概念或工程误判 | SQL 有 bag、NULL、排序等扩展 |
| INNER 与 LEFT JOIN 差在哪 | 防止概念或工程误判 | LEFT 保留左侧未匹配行 |
| WHERE 和 HAVING 差在哪 | 防止概念或工程误判 | WHERE 在聚合前,HAVING 在分组后 |
| 窗口函数为何不减少行数 | 防止概念或工程误判 | 它对窗口计算并保留输入行 |
| 如何避免 JOIN 后重复计数 | 防止概念或工程误判 | 先按目标粒度聚合或修正连接键 |
| NOT IN 为何被 NULL 影响 | 防止概念或工程误判 | UNKNOWN 会让谓词不为 TRUE |
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 查询正确性。SQL 标准描述通用语义,产品文档描述 planner、storage、locking 等实现。不要把 PostgreSQL 扩展当成所有数据库的共同保证。
9.6.3 Structure
必须掌握的接口:DDL/DML、约束、SELECT/JOIN、事务控制、EXPLAIN (ANALYZE, BUFFERS)、system catalog 与统计视图。具体重点是:relation、tuple、attribute、key、NULL、JOIN、aggregation、window。
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 与后端 辅。