Mic*_*ood 14 database-design relational-theory
我必须在现有的多对多连接中为每对添加固定数量的附加属性。跳到下图,从优点和缺点来看,选项 1-4 中哪一个是通过扩展基本案例来实现这一目标的最佳方式?或者,有没有更好的选择我在这里没有考虑过?
我目前通过中间连接表有两个多对多关系的表。我现在需要添加指向属于这对现有对象的属性的附加链接。对于每一对,我有固定数量的这些属性,尽管属性表中的一个条目可能适用于多对(甚至对于一对可以多次使用)。我正在尝试确定执行此操作的最佳方法,并且无法理清如何看待这种情况。从语义上讲,我似乎可以将其描述为以下任何一项:
我有两种对象类型,X 和 Y,每个都有唯一的 ID,还有一个objx_objy
带有列x_id
和的链接表y_id
,它们一起构成了链接的主键。每个 X 可以与许多 Y 相关,反之亦然。这是我现有的多对多关系的设置。
现在另外我在另一个表中定义了一组属性,以及一组条件,在这些条件下给定的 (X,Y) 对应该具有属性 P。条件的数量是固定的,所有对都相同。他们基本上说“在情况 C1 中,对 (X1,Y1) 具有属性 P1”,“在情况 C2 中,对 (X1,Y1) 具有属性 P2”,依此类推,对于连接中的每对的三种情况/条件桌子。
在我目前的状况正好有三个这样的条件,我也没有理由认为增加,所以一种可能性是添加列c1_p_id
,c2_p_id
以及c3_p_id
对featx_featy
,指定用于给定x_id
和y_id
,其性能p_id
在每个三种情况使用.
这对我来说似乎不是一个好主意,因为它使 SQL 复杂化以选择应用于功能的所有属性,并且不容易扩展到更多条件。但是,它确实强制要求每个 (X,Y) 对有一定数量的条件。事实上,这是这里唯一的选择。
创建条件表cond
,将条件ID添加到连接表的主键中。
这样做的一个缺点是它没有指定每对条件的数量。另一个是,当我只考虑最初的关系时,例如
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
Run Code Online (Sandbox Code Playgroud)
然后我必须添加一个DISTINCT
子句以避免重复条目。这似乎失去了每对应该只存在一次的事实。
在连接表中创建一个新的“配对 ID”,然后在第一个与属性和条件之间创建第二个链接表。
除了缺乏对每对执行固定数量的条件之外,这似乎具有最少的缺点。创建一个新的 ID 来识别除了现有 ID 之外的其他 ID 是否有意义?
与选项 3 基本相同,但没有创建附加 ID 字段。这是通过将两个原始 ID 放在新连接表中来实现的,因此它包含x_id
和y_id
字段,而不是xy_id
。
这种形式的另一个优点是它不会改变现有的表(尽管它们尚未投入生产)。但是,它基本上会多次复制整个表(或者感觉是这样),所以看起来也不理想。
我的感觉是选项 3 和选项 4 足够相似,我可以选择任何一个。如果不是因为需要少量固定数量的属性链接,我现在可能会有,这使得选项 1 看起来比其他方式更合理。根据一些非常有限的测试,DISTINCT
在我的查询中添加子句似乎不会影响这种情况下的性能,但我不确定选项 2 是否代表这种情况以及其他情况,因为放置导致的固有重复链接表的多行中的相同 (X,Y) 对。
这些选项之一是我最好的前进方式,还是我应该考虑另一种结构?
*这对我来说似乎不是一个好主意,因为它使 SQL 复杂化以选择应用于功能的所有属性......
它不一定会使查询 SQL 复杂化(请参阅下面的结论)。
......并且不容易扩展到更多条件......
它很容易扩展到更多条件,只要仍然有固定数量的条件,而不是几十个或数百个。
但是,它确实强制要求每个 (X,Y) 对有一定数量的条件。事实上,这是这里唯一的选择。*
确实如此,尽管您在评论中说这是“我的要求中最不重要的”,但您并没有说这根本不重要。
这样做的一个缺点是它没有指定每对条件的数量。另一个是,当我只考虑初始关系时……我必须添加一个 DISTINCT 子句以避免重复条目……
由于您提到的并发症,我认为您可以忽略此选项。该objx_objy
表可能是您的某些查询的驱动表(例如“选择应用于某个特征的所有属性”,我认为这意味着应用于 anobjx
或 的所有属性objy
)。您可以使用视图来预先应用DISTINCT
它,因此这不是使查询复杂化的问题,但这会在性能方面非常糟糕,而收益却很少。
创建一个新的 ID 来识别除了现有 ID 之外的其他 ID 是否有意义?
不,它没有 - 选项 4 在各方面都更好。
...它基本上多次复制整个表(或者感觉是这样),所以看起来也不理想。
这个选项很好——如果属性的数量是可变的或可能会改变,它是建立关系的明显方法
如果每个属性的数量objx_objy
可能是稳定的,并且如果您无法想象添加超过少数的额外属性,我的首选将是选项 1 。它也是唯一一个强制执行“属性数量 = 3”约束的选项——对选项 4 强制执行类似的约束可能涉及向c1_p_id
xy 表中添加……列*。
如果您真的不太关心该条件,并且您也有理由怀疑属性数量条件是否会稳定,则选择选项 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;
Run Code Online (Sandbox Code Playgroud)
查看“模拟”选项 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;
Run Code Online (Sandbox Code Playgroud)
“选择应用于功能的所有属性”:
select distinct p_id from objx_objy_prop where x_id=10 order by p_id;
/*
|p_id|
|---:|
| 90|
| 91|
| 97|
| 98|
*/
Run Code Online (Sandbox Code Playgroud)
dbfiddle在这里
归档时间: |
|
查看次数: |
5877 次 |
最近记录: |