資料庫正規化 (Database Normalization)

正規化(Normalization)是資料庫設計的過程,目的是減少資料重複、避免異常情況(新增、更新、刪除異常),並確保資料的一致性。

正規化將資料表拆分成多個較小的表,並透過關聯(Relationship)連接它們。

為什麼需要正規化?

假設有一個未正規化的訂單資料表:

訂單編號客戶名稱客戶電話產品名稱產品價格
001張一02-1234筆電30000
002張一02-1234滑鼠500
003王二03-5678筆電30000

這個設計有以下問題:

  1. 資料重複:張一的電話重複儲存,筆電的價格重複儲存
  2. 更新異常:若張一換電話,需要更新多筆記錄
  3. 刪除異常:若刪除訂單 003,會連帶遺失王二的資料
  4. 新增異常:無法單獨新增一個還沒下訂單的客戶

第一正規化 (1NF)

規則:每個欄位都必須是原子值(不可再分割),且沒有重複的欄位群組。

違反 1NF 的例子:

訂單編號產品
001筆電, 滑鼠, 鍵盤

「產品」欄位包含多個值,違反了原子性。

符合 1NF:

訂單編號產品
001筆電
001滑鼠
001鍵盤

第二正規化 (2NF)

規則:符合 1NF,且所有非主鍵欄位都必須完全相依於主鍵(消除部分相依)。

假設主鍵是(訂單編號 + 產品編號):

訂單編號產品編號客戶名稱產品名稱數量

問題:「客戶名稱」只相依於「訂單編號」,「產品名稱」只相依於「產品編號」,這就是部分相依。

符合 2NF - 拆成三個表:

訂單表

訂單編號客戶編號

產品表

產品編號產品名稱價格

訂單明細表

訂單編號產品編號數量

第三正規化 (3NF)

規則:符合 2NF,且所有非主鍵欄位都必須直接相依於主鍵(消除遞移相依)。

違反 3NF 的例子:

員工編號員工名稱部門編號部門名稱

「部門名稱」相依於「部門編號」,而非直接相依於主鍵「員工編號」,這就是遞移相依。

符合 3NF - 拆成兩個表:

員工表

員工編號員工名稱部門編號

部門表

部門編號部門名稱

正規化等級總結

正規化要求消除
1NF欄位值為原子值重複群組
2NF符合 1NF + 完全相依於主鍵部分相依
3NF符合 2NF + 直接相依於主鍵遞移相依

反正規化 (Denormalization)

雖然正規化可以減少資料重複,但也會增加查詢時需要 JOIN 的表數量,可能影響效能。

在某些情況下,會刻意保留一些重複資料來提升查詢效率,這稱為反正規化。常見情境:

  • 報表查詢需要快速存取
  • 資料倉儲或 OLAP 系統
  • 讀取遠多於寫入的應用
一般建議在設計階段先正規化到 3NF,之後再根據實際效能需求考慮是否反正規化。