多对多关系设计 - 交叉表设计

时间:2009-06-10 19:19:02

标签: sql tsql database-design

我想知道对于多对多关系的交叉表有什么更好的设计。

我正在考虑的两种方法是:

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:****请注意:我计划使用Entity Framework为数据库提供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! 

11 个答案:

答案 0 :(得分:13)

这是一个有争议的话题。我更喜欢第一种形式,因为我认为能够通过单个值查找映射行更好,并且喜欢强制执行一个可能 - 愚蠢的一致性,即在每个表中都可以使用单列主键。其他人则认为拥有该专栏是对空间的愚蠢浪费。

我们每隔几个月在新泽西州的一家酒吧见面几轮裸肩拳击。

答案 1 :(得分:10)

如果您的“交叉点”实际上是一个实体,则使用版本-1 ,这意味着:

  • 它有其他属性
  • 您可以搜索这些对象(而不是导航关系)

用户版本-2 如果它是纯粹的N-M关系表。在这种情况下还要确保:

  • 你的PK(CLUSTERED)有第一列与你的搜索更频繁的表:例如,如果你的表是Person-Address,那么我会假设你会搜索所有地址的a-a-这个地址的所有人都经常使用这个人。所以你应该把你的PK首先包含在PersonID中
  • 您仍然可以使用另一个单列UNIQUE标识符,但只需:

    1. 要么不要成为PK
    2. 或将其设为PK,但指定NON CLUSTERED,以便您可以将CLUSTERED用于覆盖两个引用列的UNIQUE索引
    3. 除非您按照设计使用GUID,否则您可以坚持使用INT IDENTITY列类型

在这两种情况下,您可能想要创建另一个覆盖2列的INDEX,但是在另一个顺序中,如果您经常从关系的另一侧进行搜索。

答案 2 :(得分:9)

第二个版本对我来说是最好的,它可以避免创建额外的索引。

答案 3 :(得分:4)

您正在构建的内容称为“交叉点”。

我非常清楚地记得我在学校的数据库教授说,交叉关系本身几乎总是一个实体,所以通常值得为它分配空间。这表明前者更“正确”。

那就是说,我个人倾向于选择后者。这真的取决于你是否会直接检索其中一个记录,或者你是否只在加入其中一个原始表时使用该表。

答案 4 :(得分:4)

如果你选择第一个,只需在PK上使用IDENTITY,就不需要浪费空间(磁盘和内存缓存)和UNIQUEIDENTIFIER。

答案 5 :(得分:3)

从开发人员的角度来看,我更喜欢前者。 处理它时更容易编写和测试。

我不需要检查两个密钥来检索唯一记录。

答案 6 :(得分:3)

如果交叉表中没有任何其他字段,它实际上不需要自己的ID,添加一个不会增加任何好处。但是,如果您要将其他字段放入该表中,并且在许多情况下,您应该将其自己的ID作为主键。

当然,经验法则,但你去了。

答案 7 :(得分:3)

回答你的第二个问题......

您只需要添加一个检查约束,如下所示:

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

答案 8 :(得分:1)

第一个的好处:

通过单个值查找连接表的功能。这使得一些查找操作在客户端更简单。

一些ORM(NHibernate)还需要每个实体中的id才能使持久性正常工作。

第二个的好处:

更简单的数据模型,无需创建其他索引。

需要更少的内存。

答案 9 :(得分:1)

第二个更好。它将接线盒(交叉盒)限制为不具有同一对的多个外观。如果接线盒中没有其他列,则无论如何都不会查找此表,除非是通过两个外键。

答案 10 :(得分:0)

鉴于TableAId-TableBId组合是唯一的,并且该表仅用于实现多对多关系,我将使用第二个选项。从纯逻辑的角度来看,第一个实现减少到第二个。从结构的角度来看,您的数据库需要维护主键/索引以及对第一个实现的约束,而第二个实例只需要保留主键/索引。