数据库设计:规范“(多对多)对多”关系


14

精简版

我必须在现有的多对多连接中为每对添加固定数量的其他属性。跳到下图,就优点和缺点而言,选项1-4中的哪一种是通过扩展基本案例来实现此目的的最佳方法?或者,还有没有在这里我没有考虑过的更好的选择?

较长的版本

我目前有一个通过中间联接表以多对多关系的两个表。现在,我需要向属于这对现有对象的属性添加其他链接。尽管属性表中的一个条目可能适用于多个对(或者甚至可以成对使用多次),但每个对都有固定数量的这些属性。我正在尝试确定执行此操作的最佳方法,并且在梳理如何思考情况时遇到了麻烦。从语义上来说,我似乎可以很好地描述以下任何一种情况:

  1. 一对链接到一组固定数量的其他属性
  2. 一对链接到许多其他属性
  3. 许多(两个)对象链接到一组属性
  4. 许多对象链接到许多属性

我有两个对象类型,X和Y,每个都有唯一的ID,以及一个objx_objy带有列x_id和的链接表y_id,它们一起构成链接的主键。每个X可以与许多Y相关,反之亦然。这是我现有的多对多关系的设置。

基本情况

基本情况

现在,我另外在另一个表中定义了一组属性,以及一组条件,在这些条件下,给定(X,Y)对应该具有属性P。条件的数量是固定的,所有对都相同。他们基本上说:“在情况C1中,对(X1,Y1)具有属性P1”,“在情况C2中,对(X1,Y1)对具有属性P2”,依此类推,对于联接中每对的三种情况/条件表。

选项1

在我目前的状况正好有三个这样的条件,我也没有理由认为增加,所以一种可能性是添加列c1_p_idc2_p_id以及c3_p_idfeatx_featy,指定用于给定x_idy_id,其性能p_id在每个三种情况使用。

选项1

在我看来,这并不是一个好主意,因为它使SQL难以选择应用于某个功能的所有属性,并且无法轻松扩展到更多条件。但是,它确实对(X,Y)对执行一定数量的条件的要求。实际上,这是这样做的唯一选择。

选项2

创建一个条件表cond,并将条件ID添加到联接表的主键中。

选项2

不利的一面是,它没有为每对指定条件数量。另一个是当我只考虑初始关系时,例如

SELECT objx.*, objy.* FROM objx
  INNER JOIN objx_objy ON objx_objy.x_id = objx.id
  INNER JOIN objy ON objy.id = objx_objy.y_id

然后,我必须添加一个DISTINCT子句以避免重复的条目。这似乎已经失去了每个对应该只存在一次的事实。

选项3

在联接表中创建一个新的“对ID”,然后在第一个与属性和条件之间建立第二个链接表。

选项3

除了缺乏对每对执行固定数量的条件外,这似乎具有最少的缺点。创建一个除了现有ID之外没有其他标识的新ID是否有意义?

选项4(3b)

与选项3基本相同,但不创建其他ID字段。这是通过将两个原始ID都放入新的联接表中来完成的,因此它包含x_idy_id字段,而不是xy_id

选项4

这种形式的另一个优点是它不会更改现有表(尽管它们尚未投入生产)。但是,它基本上多次复制整个表(或者无论如何感觉都是这样),因此似乎也不理想。

摘要

我的感觉是,选项3和4足够相似,我可以选择其中一个。如果不要求对属性进行少量固定的链接,那么到现在我可能已经有了,这使得选项1看起来比其他情况更加合理。根据一些非常有限的测试,DISTINCT在这种情况下向我的查询添加一个子句似乎不会影响性能,但是我不确定选项2和其他情况是否都代表了这种情况,因为放置会引起内在的重复链接表的多行中的相同(X,Y)对。

这些选择是我最好的前进方式,还是我应该考虑另一种结构?


我同意总的来说1和4似乎是最好的选择。使用选项4强制执行固定(3)个属性并不容易,但我认为这是可行的。
ypercubeᵀᴹ

对于该DISTINCT子句,我想到的是像#2末尾的查询那样的查询,它通过进行链接x,但未引用...。因此,如果我受了row 和的约束,那么,我将获得两个相同的查询。行和。yxycc(x_id, y_id, c_id)UNIQUE(1,1,1)(1,1,2)SELECT x.id, y.id FROM x JOIN xyc JOIN y(1,1)(1,1)
Michael Underwood

1
喔好吧。无论如何,我都会放弃选项2。我会选择1或4。
ypercubeᵀᴹ2014年

我思考得越多,我就越觉得将属性的数量限制为恰好三个对我来说是最不重要的。因此,除非在接下来的一段时间内提供其他建设性的反馈意见,否则我现在可能会选择#4。感谢您的输入,@ ypercube!
Michael Underwood

Answers:


7
  • 选项1

    *对我来说,这似乎不是一个好主意,因为它使SQL难以选择应用于功能的所有属性…

    它不一定会使查询SQL复杂化(请参见下面的结论)。

    …并且不容易扩展到更多条件…

    只要仍然有固定数量的条件,并且不存在数十个或数百个条件,它就可以轻松扩展到更多条件。

    但是,它确实对(X,Y)对执行一定数量的条件的要求。实际上,这是这样做的唯一选择。*

    确实如此,尽管您在评论中说这是“我的要求中最不重要的”,但您并没有说过这没关系。

  • 选项2

    不利的一面是,它没有为每对指定条件数量。另一个是当我只考虑初始关系时...然后我必须添加DISTINCT子句以避免重复输入...

    由于您提到的复杂性,我认为您可以取消此选项。该objx_objy表可能是某些查询的驱动表(例如,“选择应用于功能的所有属性”,我指的是应用于objx或的所有属性objy)。您可以使用视图来预先应用视图,DISTINCT因此不必担心查询复杂化,但是这将严重影响性能,几乎不会带来任何收益。

  • 选项3

    创建一个除了现有ID之外没有其他标识的新ID是否有意义?

    不,不是这样-选项4在各个方面都更好。

  • 选项4

    …基本上,它会多次复制整个表(或者无论如何感觉都是这样),所以看起来也不是很理想。

    此选项很好-如果属性的数量是可变的或可更改的,这是建立关系的明显方法

结论

如果每个属性的数量objx_objy很可能保持稳定,并且您无法想象添加的额外资源很少,我将选择选项1 。这也是强制执行“属性数量= 3”约束的唯一选项-对选项4实施类似的约束可能会涉及向c1_p_idxy表添加…列*。

如果您确实不太关心该条件,并且您也有理由怀疑属性数量条件将保持稳定,请选择选项4。

如果您不确定哪个,请选择选项1 -如其他人所说,它更简单,而且如果您有此选择,那肯定更好。如果您推迟选项1“…,因为它会使SQL复杂化以选择应用于某个功能的所有属性…”,我建议创建一个视图以提供与选项4中的额外表相同的数据:

选项1表:

create table prop(id integer primary key);
create table objx(id integer primary key);
create table objy(id integer primary key);

create table objx_objy(
  x_id integer references objx
, y_id integer references objy
, c1_p_id integer not null references prop
, c2_p_id integer not null references prop
, c3_p_id integer not null references prop
, primary key (x_id, y_id)
);

insert into prop(id) select generate_series(90,99);
insert into objx(id) select generate_series(10,12);
insert into objy(id) select generate_series(20,22);

insert into objx_objy(x_id,y_id,c1_p_id,c2_p_id,c3_p_id)
select objx.id, objy.id, 90, 91, 90+floor(random()*10)
from objx cross join objy;

查看“模拟”选项4:

create view objx_objy_prop as
select x_id
     , y_id
     , unnest(array[1,2,3]) c_id
     , unnest(array[c1_p_id,c2_p_id,c3_p_id]) p_id
from objx_objy;

“选择应用于功能的所有属性”:

select distinct p_id from objx_objy_prop where x_id=10 order by p_id;

/*
|p_id|
|---:|
|  90|
|  91|
|  97|
|  98|
*/

dbfiddle 在这里


-3

我相信这些选项中的任何一个都可以使用,但是如果条件的数量确实固定为3,我将选择选项1,否则将选择选项2。Occam的剃刀也可用于数据库设计,在所有其他因素相同的情况下,最简单的设计通常是最好的。

尽管如果您想遵循严格的数据库规范化规则,我相信无论条件数量是否固定,都需要使用2。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.