DSE ICT|关联式数据库与 SQL 备课指引(导师用)|主键外键、正规化与查询效率
- 2026-11-02
学生识抄 SELECT * FROM Student,但讲不出为何要拆表、为何要开索引。这一堂用三张表和两条成本算式,把“数据库设计”变成可以批分的判断。
本堂目标 学生能够:① 用主键与外键讲出两张表如何连接,并用 1,200 名学生中 120 人未选课(10.0%)示范孤儿记录的检查方法;② 把一张夹杂学生姓名与课程名称的选课表拆成 1NF/2NF/3NF 三张表,讲出更新异常、插入异常与删除异常各自如何消失;③ 比较全表扫描 1,200 次比较与索引 11 次,讲出查询快约 109 倍,同时讲出索引在写入与空间上的代价。
01 先备知识(开课前 3 分钟快检)
以下任何一项未过关,本堂就会卡住,先补该项:
| 技能 | 快检题 | 过关标准 |
|---|---|---|
| 资料表 | 一张表有字段与记录 | 每行一笔记录,每栏只放一种资料 |
| 对数 | 二的几次方接近 1,200 | 约 10.2,向上取整要 11 次比较 |
| 百分比 | 120 占 1,200 几成 | 10% |
02 课堂流程(60 分钟)
| 时间 | 环节 | 导师做什么 | 学生做什么 |
|---|---|---|---|
| 0–10 分 | 一张乱表 | 学生姓名、课程、导师全塞在一张表 | 指出三个重复位 |
| 10–22 分 | 主键与外键 | 独一无二 vs 指回另一张表 | 算出 120 人未选课 |
| 22–34 分 | 正规化 | 1NF、2NF、3NF 逐步拆表 | 拆成三张表 |
| 34–44 分 | SQL 查询 | WHERE、GROUP BY、HAVING、JOIN | 写出三条查询 |
| 44–54 分 | 索引与成本 | 全表扫描对比 B 树索引 | 算出快 109 倍 |
| 54–60 分 | 离场检查 | 三题即场批 | 三题全对 |
03 讲解脚本(照着说就可以)
第一幕:两张表靠一条键接上
学生表 Students 有 1,200 行,选课表 Enrolments 有 4,860 行,平均每人 4,860 ÷ 1,200 = 4.05 科。
主键是每行独一无二的识别,例如 student_id;外键是写在另一张表、指回主键的字段,例如 Enrolments.student_id。
外键管的是参照完整性:Enrolments 出现的每个 student_id,Students 必须有这一行,否则叫孤儿记录。检查很机械:SELECT COUNT(DISTINCT student_id) FROM Enrolments 得 1,080,1,200 − 1,080 = 120 人未选课,占 10.0%。
删除规则要一齐讲:ON DELETE CASCADE 会连选课一齐删,ON DELETE RESTRICT 会阻止删除。答题要写出选哪一个和理由,而不是只写“外键”。
合成主键(student_id + course_id)也是一条考点:它保证同一人同一科不会重复报名。
主键是每行独一无二的识别,例如 student_id;外键是写在另一张表、指回主键的字段,例如 Enrolments.student_id。
外键管的是参照完整性:Enrolments 出现的每个 student_id,Students 必须有这一行,否则叫孤儿记录。检查很机械:SELECT COUNT(DISTINCT student_id) FROM Enrolments 得 1,080,1,200 − 1,080 = 120 人未选课,占 10.0%。
删除规则要一齐讲:ON DELETE CASCADE 会连选课一齐删,ON DELETE RESTRICT 会阻止删除。答题要写出选哪一个和理由,而不是只写“外键”。
合成主键(student_id + course_id)也是一条考点:它保证同一人同一科不会重复报名。
要学生讲:为何 student_id 可以在 Enrolments 重复出现,但不可以重复出现在 Students(一个是外键,一个是主键)。
第二幕:拆表不是洁癖,是防止三种异常
原本一张表同时放 student_id、student_name、course_id、course_name、teacher_name。问题有三个:更新异常(改了课程名称要改 4,860 行,漏一行就前后不一致)、插入异常(新课程未有人报名就无法记录)、删除异常(删走最后一个学生,连课程资料一齐消失)。
拆成 Students(student_id、name)、Courses(course_id、course_name、teacher)、Enrolments(student_id、course_id、grade)之后:1NF 每格只有一个值;2NF 非主键字段要依赖整个合成主键,所以 grade 留在 Enrolments,course_name 搬去 Courses;3NF 去掉传递依赖,teacher 只依赖 course_id 就留在 Courses。
同一个课程资料由 4,860 次重复变成 40 行(4,860 ÷ 121.5),更新一次就一致。
代价是查询要 JOIN 两三张表,这就是“拆表换一致性”。
拆成 Students(student_id、name)、Courses(course_id、course_name、teacher)、Enrolments(student_id、course_id、grade)之后:1NF 每格只有一个值;2NF 非主键字段要依赖整个合成主键,所以 grade 留在 Enrolments,course_name 搬去 Courses;3NF 去掉传递依赖,teacher 只依赖 course_id 就留在 Courses。
同一个课程资料由 4,860 次重复变成 40 行(4,860 ÷ 121.5),更新一次就一致。
代价是查询要 JOIN 两三张表,这就是“拆表换一致性”。
要学生讲:拆表之后查询变慢,为何仍然值得(一致性与异常消失换少量 JOIN 成本)。
第三幕:索引是拿写入换读取
没有索引时,找一个 student_id 要逐行比对,最坏情况 1,200 次比较。有 B 树索引就等于每次砍一半,比较次数约 log₂1,200 ≈ 10.2,向上取整 11 次,快约 1,200 ÷ 11 = 109 倍。
但索引不是免费:每个索引要多占空间,每次 INSERT/UPDATE/DELETE 都要同时改索引,所以写入多的表不宜乱开。
几时值得开:常在 WHERE、JOIN 或 ORDER BY 出现的字段;几时不值得:只有几十行的小表、选择性极低(例如性别只有两个值)的字段。
SQL 题要按口诀写:SELECT 拣栏、FROM 拣表、WHERE 筛行、GROUP BY 分组、HAVING 筛组、ORDER BY 排序。HAVING 与 WHERE 的分别几乎每年都考:WHERE 在分组前筛行,HAVING 在分组后筛组。
但索引不是免费:每个索引要多占空间,每次 INSERT/UPDATE/DELETE 都要同时改索引,所以写入多的表不宜乱开。
几时值得开:常在 WHERE、JOIN 或 ORDER BY 出现的字段;几时不值得:只有几十行的小表、选择性极低(例如性别只有两个值)的字段。
SQL 题要按口诀写:SELECT 拣栏、FROM 拣表、WHERE 筛行、GROUP BY 分组、HAVING 筛组、ORDER BY 排序。HAVING 与 WHERE 的分别几乎每年都考:WHERE 在分组前筛行,HAVING 在分组后筛组。
要学生讲:为何在性别字段开索引帮不到多少(选择性低,仍要读大量行)。
04 必教题型与步骤
| 题型 | 例子 | 步骤 | 答案 |
|---|---|---|---|
| 设计 | 由需求画出三张表与键 | 找主体 → 定主键 → 加外键 → 检查异常 | 三表+两条外键 |
| SQL | 写查询 | SELECT → FROM → JOIN → WHERE → GROUP BY → HAVING | 语法齐全 |
| 计算 | 索引比较次数 | ceil(log2(行数)) | 11 次 |
| 解释 | 正规化消除哪种异常 | 逐层讲 1NF、2NF、3NF | 每层一个例子 |
合理性检查(一定要教):主键必须独一无二且不可为空,外键可以重复。
索引比较次数用 log₂,不是除以 2 的次数直接相加。
1,200 ÷ 11 = 109.1,不是 109 万倍;单位是“倍”不是“百分比”。
HAVING 不可以放在 GROUP BY 之前。
拆表后 JOIN 的条件要写在 ON 或 WHERE,漏写会变成笛卡儿积(1,200 × 4,860 行)。
索引比较次数用 log₂,不是除以 2 的次数直接相加。
1,200 ÷ 11 = 109.1,不是 109 万倍;单位是“倍”不是“百分比”。
HAVING 不可以放在 GROUP BY 之前。
拆表后 JOIN 的条件要写在 ON 或 WHERE,漏写会变成笛卡儿积(1,200 × 4,860 行)。
05 独立练习三题
| 题目 | 答案 | 想观察什么 |
|---|---|---|
| 1,200 名学生、4,860 条选课的平均科数 | 4.05 科 | 4,860 ÷ 1,200 |
| 1,080 人选课,几多人未选 | 120 人(10.0%) | 1,200 − 1,080 |
| 1,200 行表的索引最坏比较次数 | 11 次 | ceil(log2 1,200) |
06 学生常见错误与纠正句
| 错误 | 学生通常这样写 | 导师这样说 |
|---|---|---|
| 把外键当主键 | 答“student_id 在 Enrolments 是主键” | “Enrolments 的主键系 student_id 加 course_id,单一条 student_id 只系外键。” |
| 正规化只写“减少重复” | 答“3NF 就系不重复” | “要讲消除边种异常:更新、插入、删除,各举一个。” |
| 索引一定好 | 答“所有字段都开索引就最快” | “写入要维护索引,选择性低的字段开了帮助有限。” |
| JOIN 漏写条件 | 答“SELECT * FROM A, B” | “漏 ON 就变成 1,200 乘 4,860,答题会被扣分。” |
07 家课建议(直接指到练习卷题号)
- 中学 ICT 章节索引 数据库单元练习第 4 至 9 题
- 中学备课指引总览 其他科目对照
- 本站 ICT 练习卷专区 Paper 2 数据库部分
08 离场检查(最后 5 分钟)
| 题目 | 答案 | 判定 |
|---|---|---|
| 未选课人数与比例 | 120 人/10.0% | 三题全对=可进正规化 |
| 索引比较次数 | 11 次 | 错一题=下堂前重讲对数 |
| HAVING 与 WHERE 分别 | 分组后 vs 分组前 | 错两题以上=回到第三幕 |
09 导师常问
要背 SQL 全部语法吗?
不必。SELECT、WHERE、GROUP BY、HAVING、JOIN、ORDER BY 六个够应付大部分题目。
一定要拆到 3NF 吗?
考试答 3NF;实际系统有时为速度刻意反正规化,要讲明代价。
索引同主键有什么关系?
主键通常自动有索引,但额外索引是独立决定,要按查询模式开。
本页为 TutorZone 导师备课指引,内容由 TutorZone 团队编写;题目与流程为原创,并非任何学校或出版社的教材。


