由於 Rleational Model
要求資料庫系統能夠從資料表所有行(row)中區別出任意一行(row),所以每個資料表都應該將一個或多個列定義為主鍵,
為了要從非常多行資料中取得特定其中一行,所以做為主鍵的每個行應該都要有一個獨一無二的內容並且不能為 null
。
所以資料表一但沒有主鍵,在本次查詢中就很精準匹配零行或一行數據,因為沒有主鍵就代表沒有唯一性,所以回傳的數據可能會返回多行結果, 但並沒有強迫所有的表一定要有主鍵。
就算你把某個列設定為唯一且非空,也並不代表資料庫引擎的查詢速度會加快,你必須明確告訴資料庫哪幾個列是主鍵,另外缺少一個資料表缺少主鍵 是沒辦法跟其他表建立關聯關係的。
一個沒有主鍵的資料表會導致:
- 重複或不一致的數據產生
- 查詢效率低下
- 報表會提示相關錯誤
一個好的主鍵應該要符合幾個特徵:
- 內容必須是唯一值
- 不能為空值(null)
- 需要是穩定的,未來不可以經常更新它的值。
- 要越簡單越好,例如能用 int 就不要用 float 或 text,並且建議使用單行主鍵而不是多行主鍵
符合這些條件的常見作法是使用 Auto-increment
,它會自動生成一個無意義數值作為主鍵。
Referential integrity
(RI) 是關聯式資料庫一個很重要的概念。
Enforced RI
代表在 Child Table 中,每一個非空的外鍵值,都必須在 Parent Table 中匹配一筆對應的紀錄。
所以 Orders
表中的客戶訊息應該透過外鍵關聯另一個 Customer
表的主鍵,這樣就算有同名同姓的客戶還能用唯一的標識符來區別客戶。
為了維持兩個資料表之間的 RI,主鍵值的更新需要 cascaded 更新到所有關聯表中的子紀錄,但是 cascaded 更新會導致關聯表鎖定,所以在高併發 系統會發生問題。
所以使用有意義的主鍵未來發生變動會對系統的性能造成影響,所以乾脆建立一個無意義的主鍵這樣未來也不會產生變動這個主鍵的動機,也就不會有剛剛提到的那些更新鎖定問題。
相比之下使用文本做為主鍵可以簡化 SQL 語句,因為可以省下 joins 查詢關聯資料表關聯數值主鍵的這一段開銷。
建議不要使用複合主鍵有兩個原因:
- 定義主鍵時,有些資料庫會強制創建唯一主鍵,在多個列上創建唯一主鍵對資料庫造成額外負擔。
- 很難在多個列上使用複合主鍵做 join 查詢,速度也比較慢。
像是產品與供應商的關聯表就適合用 VendorID 和 ProductID 建立複合主鍵,因為之後做關聯查詢一定會用到其中一個列,因此會比單獨建立一個 無意義的數值主鍵更有效率,同時又能確保唯一性。
Summary
- 所有資料表都必須要用一列或多列設置為主鍵。
- 如果你擔心產生重複值的問題,可以為非主鍵欄位建立唯一索引。
- 使用越簡單越好的值做為主鍵,並且要確保未來不會變動。
- 使用複合主鍵前必須考慮清楚,應該在必要時根據業務需求來建立。