18

有趣的是我从来没有遇到过这个!

我从来没有想过一个人可以在一张桌子上建立“多对多”的关系——直到我开始研究一个用户可以互相“加好友”的系统(社交网络)。

至少在我习惯使用它的方式上,标准查找表在这里不合适。让我们保持简单:

用户表有“id”和“name”列。

User_relationship 表有“uid1”和“uid2”,表示用户是“朋友”或“芽”或“朋友”或“其他”。

很明显这里的问题是什么 - uid1 和 uid2 是来自同一个表的同一列的相同数据类型,这意味着唯一键变得有缺陷。

例如:uid1 = 1 uid2 = 2

是相同的:

uid1 = 2 uid2 = 1

因此可能返回 2 条记录,如果查询执行错误则返回 0 条记录。

本着良好设计表格的精神,我不想扫描整个表格两次以检查现有值。

有什么技巧可以解决这个问题吗?这是一个我从未想过的设计问题,这让我很恼火,因为我知道有一些简单的技巧可以让它发挥作用。

在你问之前,我还没有尝试过任何东西,因为我已经看到我最喜欢的关联事物的方式(查找表)不足以满足我的需求,我需要一些帮助——我在 SO 或 Google 上找不到任何东西:(

提前致谢。

4

4 回答 4

11

如果您描述的关系是对称的,如“Bob 是 Joe 的朋友”的意思是“Joe 也是 Bob 的朋友”,那么您可以在代码中确保 2 个用户 ID 中较小的一个继续第一列,较大的列在第二列。这个约束几乎可以确保查找表中的记录是唯一的。这也意味着当您执行查找时,您通常必须搜索两列。

例如,如果您尝试获取 Bob 的所有朋友,则必须查询任一列中包含 Bob 的 ID 的记录。这会导致更多的代码,并可能对性能产生影响。

如果关系可能是不对称的,例如“Bob 是 Joe 的朋友”并不一定意味着“Joe 也是 Bob 的朋友”,那么您需要为每对用户输入 2 个条目:Bob - Joe 和 Joe - Bob。这意味着您的查找表将包含两倍的条目,并且您的网站对跟踪者非常友好 :D 当然,即使您的关系是对称的,您仍然可以选择应用此系统。

使用这种方法,如果您想获取 Bob 的所有朋友,您只需在第一列中选​​择带有 Bob 的 ID 的记录。这可能意味着更快的查找和更少的代码供您编写,但同样,这意味着您在数据库中占用了更多空间。

于 2013-06-15T22:44:37.853 回答
10

意味着唯一的键变得有缺陷。

uid1 = 1 uid2 = 2

是相同的:

uid1 = 2 uid2 = 1

不,不是。

例如,在 Facebook 上,我有一些客户发送了成为“朋友”的请求,但我从未接受过……因为他们只是熟人。

同样,我可能将一些人标记为最好的朋友,但他们没有回报,反之亦然。或者也许我忽略了一些,而他们不是。

基本上,(uid1, uid2)元组中的信息比单纯的 ID 多得多。

uid1 < uid2在决定在表上添加例如约束之前,请确保您永远不需要处理此类情况。

于 2013-06-15T22:28:05.647 回答
2

这并不少见。

通常所做的是有一个表,就像在大多数多对多关系中一样,它由构成主键的两个表的两列组成,每列是一个 id。

正如你所说的userId1和userId2。如有必要,可以将属性添加到关系中(例如友谊的分类)。

当用户 1 与用户 2 成为朋友时,通常有两个插入,(1,2) 和 (2,1)。

与取消好友相同的事情,需要两次删除。

您最终可能会得到一个用户将自己作为朋友,这可能对系统的实际工作至关重要。如果用户只能查看他朋友的照片,那么如果他不是他自己的朋友,一些系统可能不允许他查看他自己的照片。

它非常依赖于应用程序是如何在数据库之上编写的。

于 2013-06-15T22:30:45.330 回答
1

我同意其他人所说的,为一段关系插入 2 个插页(1:2 和 2:1)并不是一个坏主意。这实际上有助于扩展现代社交网络中常见的一些功能。我能想到的一些实际使用案例是关系或其他属性的描述。虽然个人仍然是朋友,但他们彼此之间保持着不同的环境。在 1:2 关系中,Bob 正在关注 Joe 的更新并将他放在最好的朋友列表中(添加 bff 列),而在 2:1 中,Joe 没有 Bob 在 bff 列表中并且不关心关注他的帖子(以下列) .

于 2013-10-28T20:44:53.820 回答