說明資料庫正規化基本概念

本文說明初學者應該了解的資料庫正規化術語。 對此術語有基本了解將有助於探討關聯式資料庫的設計。

正規化說明

正規化是在資料庫中組織資料的程序。 其中包括根據設計來保護數據的規則,建立數據表和建立這些數據表之間的關聯性,並藉由消除備援和不一致的相依性,讓資料庫更有彈性。

重複的資料會浪費磁碟空間,並產生維護方面的問題。 如果必須變更現有資料,並且該資料的位置超過一個以上,就必須在所有位置上以完全相同的方式進行變更。 如果該數據只儲存在 Customers 數據表中,而且資料庫中沒有其他數據,客戶地址變更就更容易實作。

何謂「不一致的相依性」? 雖然使用者在 [客戶] 資料表中查看特定客戶的位址是直覺的,但尋找該客戶上呼叫的員工薪資可能沒有意義。 員工的薪資與該名員工相關,也就是所謂相依,因此應該移到 [員工] 資料表中。 不一致的相依性會讓資料難以存取,因為查找資料的路徑可能會遺失或中斷。

資料庫正規化有一些規則。 每個規則都稱為「一般形式」。如果觀察到第一個規則,則表示資料庫為「第一個一般形式」。如果觀察到前三個規則,資料庫會被視為「第三個正常形式」。雖然可以進行其他正規化層級,但第三個標準形式會被視為大部分應用程式所需的最高層級。

如同許多正式規則和規格,真實世界案例不一定會允許完美合規性。 一般而言,正規化需要其他資料表,有些客戶也會嫌麻煩。 如果您決定違反正規化前三個原則中的其中一個原則,請確定您的應用程式能夠掌握所有可能發生的問題,例如重複的資料與不一致的相依性。

下列說明包括範例。

第一正規形式

  • 刪除各個資料表中的重複群組。
  • 為每一組關聯的資料建立不同的資料表。
  • 使用主索引鍵識別每一組關聯的資料。

請勿在單一數據表中使用多個字段來儲存類似的數據。 例如,要追蹤來自兩個可能來源的存貨項目,存貨記錄會包含 [廠商代碼 1] 與 [廠商代碼 2] 欄位。

當您增加第三個廠商時,會發生什麼狀況? 新增欄位不是答案;它需要程式和數據表修改,而且無法順暢地容納動態數目的廠商。 您應該採取另外一種作法,就是將所有廠商資料另外放置在不同的資料表中 (稱為 [廠商]),然後使用項目編號索引鍵,將存貨連結至廠商;或使用廠商代碼索引鍵將廠商連結至存貨。

第二正規形式

  • 為可套用於多筆記錄的多組值建立不同的資料表。
  • 使用外部索引鍵,讓這些資料表產生關聯。

如有必要,記錄不應相依於數據表的主鍵以外的任何專案, (複合索引鍵) 。 以會計系統中的客戶地址為例。 [客戶] 資料表需要地址,但 [訂單]、[送貨]、[發票]、[應收帳款] 與 [會計] 資料表也都需要地址。 不要將客戶地址儲存為這些資料表中的不同項目,而是儲存在一個位置,例如儲存在 [客戶] 資料表或另外一個 [地址] 資料表中。

第三正規形式

  • 排除不相依於索引鍵的欄位。

不屬於該記錄索引鍵之記錄中的值不屬於數據表。 一般而言,只要欄位群組的內容可以套用至資料表中一筆以上的記錄時,您就可以考慮將這些欄位放置在單獨的資料表中。

例如,在 [員工招募] 資料表中,會包含某位求職者的學院名稱與地址。 但是您需要完整的學院清單,以整批寄送郵件。 如果學院資訊儲存在 [求職者] 資料表中,就無法列出不含目前求職者的學院清單。 因此,您應該要另外建立 [學院] 資料表,然後再使用學院代碼索引鍵連結至 [求職者] 資料表。

例外狀況:雖然理論上需要遵守第三個一般形式,但並非總是實際的。 如果您有 [客戶] 資料表,並且想要刪除所有可能的欄位間相依性,則必須分別為城市、郵遞區號、銷售人員、客戶類別,以及其他可能會在多筆記錄中重複的因素,建立不同的資料表。 理論上,正規化值得一提。 但是太多小型資料表可能會降低效能,或超過可開啟的檔案與記憶體容量。

比較可行的方法是只針對變更頻繁的資料運用第三正規形式。 如果保留某些相依的欄位,請將應用程式設計為要求使用者在欄位變更時,驗證所有相關聯的欄位。

其他正規化形式

第四個一般窗體,也稱為 Boyce-Codd Normal Form (BCNF) ,第五個一般窗體確實存在,但在實際設計中很少考慮。 忽略這些規則可能會導致資料庫設計較不完美,但不應影響功能。

正規化範例資料表

下列步驟示範將虛構學生資料表正規化的程序。

  1. 未正規化的資料表:

    學號 導師 導師辦公室 課程 1 課程 2 課程 3
    1022 Jones 412 101-07 143-01 159-02
    4123 Smith 216 101-07 143-01 179-04
  2. 第一正規形式:沒有重複群組

    資料表應該只有兩個維度。 因為一個學生會上數種課程,所以課程應該另列資料表。 因此,上述資料中的欄位 [課程 1]、[課程 2] 和 [課程 3] 即是設計問題所在。

    電子表格通常會使用第三個維度,但數據表不應該使用。 另一種查看此問題的方式是使用一對多關聯性,不要將一端和多端放在同一個數據表中。 相反地,請排除 Class#) (重複群組,以第一個標準形式建立另一個數據表,如下列範例所示:

    學號 導師 導師辦公室 課程 #
    1022 Jones 412 101-07
    1022 Jones 412 143-01
    1022 Jones 412 159-02
    4123 Smith 216 101-07
    4123 Smith 216 143-01
    4123 Smith 216 179-04
  3. 第二正規形式:刪除重複資料

    請注意上表中每個 Student# 值的多個 Class# 值。 Class# 在功能上並不相依於 Student# (主鍵) ,因此此關聯性不是第二般形式。

    下列資料表示範第二正規形式:

    學生:

    學號 導師 導師辦公室
    1022 Jones 412
    4123 Smith 216

    註冊課程:

    學號 課程 #
    1022 101-07
    1022 143-01
    1022 159-02
    4123 101-07
    4123 143-01
    4123 179-04
  4. 第三正規形式:刪除不取決於機碼的資料

    最後一個範例中,[導師辦公室] (導師的辦公室編號) 在運用時會依賴 [導師] 屬性。 而解決的方法,就是將該屬性從 [學生] 資料表移至 [教職員] 資料表,如下所示:

    學生:

    學號 導師
    1022 Jones
    4123 Smith

    教職員:

    名稱 辦公室 部門
    Jones 412 42
    Smith 216 42