没有中间表的多对多 - 是否可能?

时间:2009-12-13 13:24:07

标签: database many-to-many

我有两个通常具有一对多关系的实体,但在极少数情况下应该有机会成为多对多关系。 我不想为每个查询加入带有中间表的表 - 我猜有“罕见的多对多”的优选模式, - (可能有m-t-m的附加表,有重复记录或其他东西)。有什么想法吗?

UPD。好吧,首先我考虑中间表的潜在开销(可能我高估它),第二个是表达真实世界的语义,通常对象应该具有一对多的关系。

7 个答案:

答案 0 :(得分:13)

“罕见的多对多”关系仍然是M:M关系,应该正确建模。这涉及创建将两个表链接在一起的中间表或关联表。您的查询稍微复杂一些,但只涉及额外的连接。但是,如果您正确地模拟了表格,那么您将获得同行的满意和钦佩:)

兰迪

答案 1 :(得分:3)

多对多关系有什么问题?这是解决问题的最简单方法,如果索引设置正确,加入表格会非常快。并且不用担心编码时间 - 您可以将连接分解出来,这样您只需要编写一次。如果您使用类似Linq的软件,则可以存储子查询。如果要手动构建SQL字符串,仍然可以将子查询存储为程序中的某个const字符串。

但是,您可以通过创建两个“Primary Child”和“Secondary Child”列来避免额外的表,其中primary child为NOT NULL,Secondary Child为NULLable。如果您不关心多个匹配项的可能性,请仅选择主要子项。在极少数情况下,请选择两个孩子。

答案 2 :(得分:2)

  

好吧,首先我想到中间表的潜在开销(也许我高估了它)

我想你做到了。索引连接是数据库特别擅长的。

  

第二个是关于表达现实世界的语义,通常对象应该具有一对多的关系。

嗯,如果没有一个更具体的例子我们就无法回答这个问题:通常的一对多关系的性质与多对多的“特殊情况”有什么不同?在多对多发生的地方,特别是映射的一个之间的关系是否有所不同?如果是这样,对于一个映射有一个单独的行内引用可能是有意义的,并且有一个用于额外映射的连接表。

但是,如果它只是同一种关系 - 只是一个通常但并不总是一对多 - 那么它仍然是一个多对多的关系,并将其建模为任何其他方式将是为自己的背部制作杆。您最终必须首先检查一对多关系,然后检查多对多以及更多开销,这将是一个更复杂的查询。

答案 3 :(得分:1)

我将假设您的问题是关于关系(例如SQL)数据库。如果要以“正常”形式对表进行建模,则需要中间表。但是,在没有正常性限制的情况下,您可以使用具有m * n行的单个表对您的案例建模(如果您有表A,中间表和表B,则为内连接的结果。这在数据仓库中非常有用操作,但如果表经常删除,更新或插入行,我不会建议使用此策略。

答案 4 :(得分:0)

通常,您将无法避开中间表。无论你做什么来使一对多的情况变得更容易,你只需花费更多精力来处理一般情况下的正确情况。

答案 5 :(得分:0)

如果某事通常是一对多但有时是多对多的关系,那么它只是一种多对多的关系,而不是一种暂时的中间关系。中间表有什么问题 - 我在这里假设表现。我发现如果你使用快速比较的数据类型(例如整数)和正确的索引,那么多对多模型将非常有效地扩展。如果这仍然是一个问题,那么可以考虑修改您的架构,例如多对多实体是否与通常的一对多实体完全相同,还是它们应该是分开的表?

答案 6 :(得分:0)

避免关联表的一种方法是让每个主表包含类似于另一个表中的一组交叉引用条目 - 假设您的DBMS甚至支持这样的构造。由于许多原因,它无穷无尽,尤其是自动查询或更新正确的列表非常困难。

大纲架构:

create table t1 (id integer, xref_t2 set(integer), ...other columns...);
create table t2 (id integer, xref_t1 set(integer), ...other columns...);

请注意,没有简单的方法来声明参照完整性约束,以确保'xref_t2'中的值确实仍然有效(或者编写触发器来强制执行约束)。

替代机制,例如普通交叉引用的非可空列(每个表中有一个)和不常见的多个交叉引用的可空列(同样,每个表中有一个)仍然运行更多的犯规不常见的情况,它不是1:2,而是1:3或1:4的关系。

最好的方法是使用显式关联表。