2009-06-10 68 views
22

我想知道什麼是多對多關係的交集表更好的設計。多對多關係設計 - 交叉表設計

我正在考慮這兩種方法:

CREATE TABLE SomeIntersection 
(
    IntersectionId UNIQUEIDENTIFIER PRIMARY KEY, 
    TableAId UNIQUEIDENTIFIER REFERENCES TableA NOT NULL, 
    TableBId UNIQUEIDENTIFIER REFERENCES TableB NOT NULL, 
    CONSTRAINT IX_Intersection UNIQUE(TableAId, TableBId) 
) 

CREATE TABLE SomeIntersection 
(
    TableAId UNIQUEIDENTIFIER REFERENCES TableA NOT NULL, 
    TableBId UNIQUEIDENTIFIER REFERENCES TableB NOT NULL, 
    PRIMARY KEY(TableAId, TableBId) 
) 

有沒有好處,一個比其他?
編輯2:****請注意:我打算使用實體框架爲數據庫提供一個API。考慮到這一點,一種解決方案與EF相比能夠更好地發揮作用嗎?

編輯:在一個相關的說明,對於一個交叉表,兩列引用相同的表(下面的例子),有沒有辦法使兩個字段不同的記錄?

CREATE TABLE SomeIntersection 
(
    ParentRecord INT REFERENCES TableA NOT NULL, 
    ChildRecord INT REFERENCES TableA NOT NULL, 
    PRIMARY KEY(TableAId, TableBId) 
) 

我想阻止以下

ParentRecord   ChildRecord 
================================= 
     1     1   --Cyclical reference! 
+3

爲了防止你的榜樣(這被稱爲「自我參照」),就足以在桌子上水平「增加一個檢查約束ALTER TABLE dbo.SomeIntersection ADD CONSTRAINT CHK_SomeIntersection_SelfRefNoNoNoNo CHECK(ParentRecord <> ChildRecord)「 ---但你不會以這種簡單的方式解決案例A-> B-> C-> A. – van 2009-06-11 18:14:00

+0

我比較關心引用,更擔心自引用,謝謝! – 2009-06-11 18:22:19

回答

9

第二個版本對我來說是最好的,它避免了創建額外的索引。

+0

我接受了這個答案,因爲它最適合實體框架。交叉點/交叉表很好地摺疊到模型中生成的實體中。 – 2009-06-15 21:22:08

+1

如果你想訪問表B中的交點表,你將需要第二個版本的另一個索引。 – 2010-05-23 13:46:02

12

它的一些爭論的話題。我更喜歡第一種形式,因爲我認爲能夠通過單個值來查找映射行更好,並且希望強制實現在每個表中可用的單列主鍵的可能愚蠢的一致性。其他人認爲擁有這一欄是對空間的一種愚蠢浪費。

我們每隔幾個月在新澤西的一家酒吧舉行幾輪裸指拳擊。

+3

我同意一行的身份可以相當方便,特別是如果有一段時間你需要直接參考相關性。 +1裸拳拳擊,DBA撲滅俱樂部的第一條規則... – CAbbott 2009-06-10 19:30:45

+2

@混亂@恰好放在。我更喜歡後者,但仍然投票支持你。挖掘啤酒,謝謝:) – onedaywhen 2009-06-11 13:31:55

+1

它可能值得注意實體框架對待PK'less描述表不同於PK'd表 – hanzolo 2017-03-18 07:39:41

4

你正在建造的東西叫做「十字路口」。

我對我的數據庫教授在學校有一個非常清楚的記憶,即交叉關係幾乎總是一個實體,因此它通常值得爲它分配空間。這表明前者更「正確」。

這就是說,我個人傾向於選擇後者。這實際上取決於您是否會直接檢索這些記錄中的一個,或者您是否只在加入其中一個原始表時使用該表。

3

從開發者的角度來看,我更喜歡前者。 處理它時編寫和測試會更容易。

我不需要檢查兩個鍵來檢索唯一的記錄。

4

如果與第一個一起使用,只需在PK上使用IDENTITY,則不需要使用UNIQUEIDENTIFIER浪費空間(磁盤和內存高速緩存)。

3

如果在交集表中沒有任何其他字段,它確實不需要它自己的ID,並且添加一個並不會帶來任何好處。但是,如果您打算將其他字段放入該表中,並且在很多情況下您會將其自己的ID作爲主鍵。

經驗法則,當然,但你去。第一個

1

優點:

由單一值來查找連接表的能力。這使得在客戶端上的一些查找操作更簡單。

某些ORM(NHibernate)也需要每個實體中的ID以使持久性正常工作。第二個的

優點:

簡單的數據模型,而不需要創建額外的索引。

需要更少的內存。

1

第二個比較好。它將接線盒(交叉盒)限制爲不具有同一對的多個外觀。如果接線盒中沒有其他列,則無論如何您都不會查找此表,除非通過兩個外鍵。

0

鑑於TableAId-TableBId組合是唯一的,並且該表僅用於實現多對多關係,所以我將使用第二個選項。從純邏輯的角度來看,第一個實施方案減少到第二個。從結構角度來看,您的數據庫需要維護主鍵/索引以及第一個實現的約束,並且只需維護主鍵/索引即可。

10

使用版本1,如果你的「交集」,實際上是對自己的實體,這意味着:

  • 它有附加屬性
  • 您可以搜索的對象(而不是導航的關係)

用戶版本-2如果它是純粹NM關係表。在這種情況下,請確保:

  • 您有您的PK(CLUSTERED)第一列與您的搜索更頻繁地關聯:例如,如果您的表是Person-Address,那麼我會假設您會更頻繁地尋找所有人的地址,然後爲所有人在此地址尋找。所以,你應該把你的PK,包括是PersonID第一
  • 你仍然可以有另外一列的唯一標識符,但只是:

    1. 要麼不使它成爲一個PK
    2. 或使它成爲一個PK,但指定非羣集的,這樣就可以對覆蓋兩個引用列
    3. ,除非你用你的設計的GUID唯一索引使用羣集的,然後你可以堅持到INT IDENTITY列類型

在這兩種情況下,您可能都希望創建另一個INDEX覆蓋2列,但以另一種順序,如果您經常從關係的另一側進行搜索。

3

回答你的第二個問題...

你只需要添加一個檢查約束,就像這樣:

CREATE TABLE SomeIntersection 
(
    ParentRecord INT REFERENCES TableA NOT NULL, 
    ChildRecord INT REFERENCES TableA NOT NULL, 
    PRIMARY KEY(TableAId, TableBId), 
    CHECK (ParentRecord <> ChildRecord) 
)