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 團隊編寫;題目與流程為原創,並非任何學校或出版社的教材。


