正規化是關聯式資料庫設計的基石,旨在消除資料冗余、避免異常、確保一致性。本文深度解析 1NF、2NF、3NF 定義、判斷標準、違反後果與實務取捨策略。
定義:關聯式資料表的每個屬性(欄位)皆為不可再分割的原子值;不存在重複群組(同一實體的多值屬性)。
| 違反範例 | 問題 | 正規化方案 |
|---|---|---|
| address 欄位存「台灣、台北市、信義區、信義路五段 7 號」 | 單欄位含多語義,難以查詢/索引/統計 | 拆分為 country、city、district、street、number 獨立欄位 |
| product 表含 img1、img2、img3...img10 欄位 | 重複群組,新增圖片需 ALTER TABLE,查詢需 UNION | 建立 product_images 子表(product_id, img_url, sort_order),一對多關聯 |
檢核清單:□ 無複合欄位 □ 無重複欄位群 □ 每欄位單一語義 □ 有主鍵唯一識別列
定義:滿足 1NF,且所有非主鍵屬性完全函數相依於「整個」主鍵(無部分相依)。
| 違反範例 | 問題 | 正規化方案 |
|---|---|---|
| order_items (order_id, product_id, product_name, qty, price) PK=(order_id, product_id) product_name 只相依 product_id | 同一商品在不同訂單重複儲存名稱;修改名稱需更新多列;刪除訂單可能遺失商品資訊 | 拆分 products 表 (product_id PK, product_name);order_items 保留 (order_id, product_id, qty, price) FK 關聯 products |
| student_course (student_id, course_id, student_name, course_name, score) PK=(student_id, course_id) | 學生姓名只相依 student_id,課程名稱只相依 course_id | 拆分 students、courses 主檔;student_course 僅保留 FK 與 score |
關鍵判斷:若主鍵為單欄位,自動滿足 2NF。僅複合主鍵表需檢查。
定義:滿足 2NF,且無非主鍵屬性傳遞相依於主鍵(即:非主鍵不相依於其他非主鍵)。
| 違反範例 | 傳遞鏈 | 正規化方案 |
|---|---|---|
| employees (emp_id PK, dept_id, dept_name, dept_manager) emp_id → dept_id → dept_name | emp_id → dept_id(非主鍵) → dept_name(非主鍵) | 拆分 departments (dept_id PK, dept_name, dept_manager);employees 保留 dept_id FK |
| orders (order_id PK, user_id, user_city, user_province) order_id → user_id → user_city | order_id → user_id(非主鍵) → user_city(非主鍵) | 拆分 users (user_id PK, city, province);orders 僅保留 user_id FK |
當候選鍵有多個且重疊時,3NF 可能仍存異常。BCNF 要求:所有決定因素皆為候選鍵。實務中 3NF 通常足夠,BCNF 針對極少數複雜鍵結構。
| 場景 | 建議 | 理由 |
|---|---|---|
| 核心交易系統(訂單、帳戶、庫存) | 嚴格 3NF | 資料一致性優先,寫入頻繁,異常成本極高 |
| 報表/分析/數據倉儲 | 適度反正規化(星型/雪花模型) | 查詢效能優先,讀多寫少,可接受受控冗余 |
| 高併發讀取熱點表(商品詳情、用戶檔案) | 冗余常用欄位(如 category_name 直接存商品表) | 避免 JOIN 開銷,需配合快取/訊號機制同步 |
| 快速迭代 MVP 階段 | 優先交付,事後重構 | 過度設計延遲上線,技術債務可控前提下可接受 |
範式是指導原則而非教條。優秀的資料架構師會在「資料完整性、擴展性、查詢效能、開發效率」四維度動態平衡,依業務階段與訪問模式做出最佳取捨。記住:任何違反範式的設計,最終都會以技術債務的形式被償還——關鍵在於你是否有計畫、有預算、有時間去償還它。