正規化是關聯式資料庫設計的基石,旨在消除資料冗余、避免更新異常、確保資料完整性。本文逐階解說 1NF 至 BCNF,並說明實務取捨。
規則: 每個欄位不可再分,單一欄位不含多值、不含重複群組。
違反範例: tags 欄位存 "tag1,tag2,tag3"
修正: 拆分為 article_tags 關聯表,每列一個標籤。
前提: 已符合 1NF,且擁有複合主鍵 (PK)。
規則: 非鍵屬性必須「完全相依」於整個主鍵,而非部分鍵。
違反範例: order_items (order_id, product_id, product_name),product_name 僅相依 product_id。
修正: 將 product_name 移至 products 表。
規則: 非鍵屬性不得傳遞相依於主鍵 (即:非鍵 → 非鍵)。
違反範例: employees (emp_id, dept_id, dept_name),dept_name 相依 dept_id,而 dept_id 相依 emp_id。
修正: 抽離 departments (dept_id, dept_name) 表。
規則: 對於任何決定因子集合 X → Y,X 必須包含候選鍵。換句話說:「每個決定因子都是候選鍵」。
3NF 與 BCNF 差異範例:
-- 學生-課程-教師,一位教師只教一門課
student_course (student_id, course_id, teacher_id)
候選鍵:(student_id, course_id) 、 (student_id, teacher_id)
FD:teacher_id → course_id
teacher_id 不是候選鍵 → 違反 BCNF
-- 拆分:
teachers (teacher_id, course_id)
student_teacher (student_id, teacher_id)
實務上常為查詢效能適度反正規化:
| 場景 | 手法 | 風險 |
|---|---|---|
| 頻繁 JOIN 大表 | 冗余欄位 (如訂單表存 customer_name) | 更新時需同步多表,需觸發器或應用層保證 |
| 彙總報表 | 物化視圖 / 摘要表 | 資料非即時,需定期重建 |
| 層級結構查詢 | Closure Table / Path Enumeration | 寫入複雜度上升 |
原則: 先正規化至 3NF/BCNF,再針對證實的熱點查詢局部反正規化,並建立資料一致性機制。
正規化提供清晰、可維護的資料骨架;反正規化則是針對特定效能瓶頸的手術刀。掌握 1NF→BCNF 邏輯,配合實務取捨,才能設計出既健壯又高效的 MySQL 資料模型。