BCNF 保證無損 join,但不保證保持相依
「實務上做到 BCNF 就停」的真正理由不是 4NF/5NF 太難,而是 BCNF 本身就有代價 — 而且這個代價常常讓人選擇刻意停在 3NF。
排課表(老師 → 課程 違反 BCNF,見 BCNF 拿掉 3NF「只檢查非鍵值欄位」的前提)拆成 BCNF:
授課表(老師, 課程)
選課表(學生, 老師)
join 回去剛好是原表,無損。但原本那條約束 (學生, 課程) → 老師 — 一個學生一門課只能分到一位老師 — 現在沒有任何一張表檢查得到:
| 選課表 | 合法嗎 |
|---|---|
| (小明, 張老師) | 單看這張表:合法 |
| (小明, 李老師) | 單看這張表:合法 |
兩位老師都教資料庫,合起來就是「小明同一門課被分配兩位老師」。兩張表各自都沒違規,違規發生在它們之間,只能靠 join 檢查或應用層擋。
可以直接拿來用的判準:
| 無損 join | 保持相依 | |
|---|---|---|
| 3NF | ✅ 永遠可達成 | ✅ |
| BCNF | ✅ | ❌ 不保證 |
所以正規化推到後面會變成取捨:消掉重複,還是讓約束留在 DB 層檢查得到,有時候只能二選一。這也是 反正規化要排在索引與物化視圖後面 的鏡像 — 兩邊都在講「更正規 / 更不正規都要算帳,不是愈高階愈好」。