2008-09-02 98 views
14

我在我的數據庫中的以下表中有不少一對多的關係,這是由具有外鍵到每個主表的主鍵連接表表示:多對多表中的一個或兩個主鍵?

  • 小工具:爲widgetid(PK),標題,價格
  • 用戶:用戶ID(PK),名字,姓氏

假定每個用戶的Widget組合是唯一的。我可以看到如何構造所述連接表,定義了數據關係的兩個選項:

  1. UserWidgets1:UserWidgetID(PK),爲widgetid(FK),用戶ID(FK)
  2. UserWidgets2:爲widgetid(PK,FK ),UserID(PK,FK)

選項1具有主鍵的單個列。但是,這似乎沒有必要,因爲表中存儲的唯一數據是兩個主表之間的關係,並且這種關係本身可以形成唯一的關鍵字。因此導致選項2,其具有兩列主鍵,但丟失了選項1具有的一列唯一標識符。我也可以有選擇地在第一個表中添加一個兩列唯一索引(WidgetID,UserID)。

兩個性能明智之間還是有任何真正的區別,或者是爲了構建UserWidgets多對多表而選擇一種方法而不是其他理由?

+0

您需要的索引取決於您的查詢需求,而不是您的模式設計。 – dkretz 2011-11-02 07:32:14

回答

24

無論哪種情況,您只有一個主鍵。第二個是所謂的複合鍵。推出新專欄沒有什麼好的理由。實際上,您必須在所有候選鍵上保留一個唯一的索引。添加一個新列只會給您帶來維護費用。

去與選項2

+0

主鍵可以複合 - 這些術語不是唯一的。 – paulmurray 2009-03-22 02:34:44

+2

@paulmurray:我相信上面的答案表示在任何一種情況下都有一個主鍵,包括您有複合鍵的情況。你有什麼補充嗎? – Apocalisp 2009-03-22 05:32:00

0

由於每個User-Widget組合都是唯一的,因此應該通過使組合具有唯一性來在表中表示該組合。換句話說,請使用選項2.否則,您可能有兩個具有相同小部件和用戶標識但具有不同用戶小部件標識的條目。

0

不需要在第一個表中userwidgetid,像你說的獨特性來自於爲widgetid和用戶ID的組合。

我會使用第二個表,保留foriegn鍵,並在widgetid和userid上添加唯一索引。

所以:

 
userwidgets(widgetid(fk), userid(fk), 
      unique_index(widgetid, userid) 
) 

中有沒有多餘的主鍵,因爲該數據庫將不需要計算爲重點的指數有些性能與增益。在上面的模型中,儘管這個索引(通過unique_index)仍然是計算的,但我相信這更容易理解。

2

在這種情況下主鍵有什麼好處?考慮沒有主鍵的選項: UserWidgets3:WidgetID(FK),UserID(FK)

如果您想要唯一性,那麼請使用複合鍵(UserWidgets2)或唯一性約束。

擁有主鍵的常見性能優勢是您經常通過快速的主鍵查詢表。在多對多的表中,你通常不用主鍵查詢,因此沒有性能優勢。多對多的表由它們的外鍵查詢,因此您應該考慮在WidgetID和UserID上添加索引。

2

選項2是正確的答案,除非您有充分的理由添加代理數字鍵(您已在選項1中完成)。

替代數字鍵列不是「主鍵」。主鍵在技術上是用於唯一標識表中的記錄的列的組合之一。

任何構建數據庫的人都應該閱讀Josh Berkus的文章http://it.toolbox.com/blogs/database-soup/primary-keyvil-part-i-7327以瞭解代理數字鍵列和主鍵之間的區別。

根據我的經驗,向表中添加代理數字鍵的唯一真正原因是您的主鍵是複合鍵,並且需要在另一個表中用作外鍵引用。只有這樣,你甚至應該考慮在表中添加一個額外的列。

每當我看到一個數據庫結構,其中每個表都有一個'id'列時,它可能是由不關心關係模型的人設計的,它總會顯示一個或多個Josh's文章。

3

我同意以前的答案,但我有一句話要補充。 如果你想添加更多的信息給關係,並允許相同的兩個實體之間的更多關係,你需要選項一。

例如,如果您想跟蹤用戶1在userwidget表中使用小部件664的所有時間,則userid和widgetid不再是唯一的。

5

就個人而言,我會合成許多一對多表/代理鍵列,原因如下:

  • 如果你已經使用數字合成鍵在實體表則具有同樣的關係表保持設計和命名慣例的一致性。
  • 將來可能會出現這樣的情況:多對多表本身成爲需要對單個行進行唯一引用的下級實體的父實體。
  • 它不會真的使用那麼多額外的磁盤空間。

的合成關鍵是不是替換自然/化合物鍵也不成爲PRIMARY KEY該表只是因爲它是在該表的第一列,所以部分地與約什Berkus如是文章同意。然而,我不同意自然鍵永遠是PRIMARY KEY's的好選擇,當然,如果它們被用作其他表中的外鍵,肯定不應該使用。

5

選項2使用簡單的複合鍵,選項1使用surrogate key。選項2在大多數情況下是首選,並且接近國家模式,因爲它是一個很好的候選關鍵。

有,你可能需要使用一個代理鍵(選項1)

  1. 你是不是該化合物關鍵是隨着時間的推移一個很好的候選鍵的情況。特別是對於時間數據(隨時間變化的數據)。如果你想用UserId和WidgetId添加另一行到UserWidget表?想想就業(EmployeeId,EmployeeId) - 它在大多數情況下都可以工作,除非有人在以後再次爲同一僱主工作
  2. 如果您正在創建消息/業務交易或類似的需要更簡單的密鑰用於集成。複製可能?
  3. 如果您想創建自己的審計機制(或類似的),並且不想讓密鑰變得太長。

作爲一個經驗法則,在建模數據時,您會發現大多數關聯實體(多對多)是事件的結果。人員就業,項目被添加到籃子等等。大多數事件對事件具有時間上的依賴性,其中日期或時間是相關的 - 在這種情況下,代理鍵可能是最佳選擇。

因此,採取選項2,但確保你有完整的模型。

1

我會與兩個去。

聽我說:

的複合鍵顯然是到目前爲止去爲反映您的數據去的意思很好的,正確的方法。沒有問題。

但是:除非您使用單個生成的主鍵 - 代理鍵,否則我有各種各樣的麻煩使得休眠正常工作。

所以我會使用邏輯和物理數據模型。邏輯之一有複合鍵。物理模型 - 實現邏輯模型 - 具有代理鍵和外鍵。