如何存储在像MySQL一个RDBMS双向关系?(How to store bidirectional

2019-06-24 23:34发布

假设我要存放我的应用程序的用户,与Facebook类似,本身之间的关系。

这意味着,如果AB的朋友(或某种关系),则B也是A的朋友。 为了保存这个关系目前我打算将它们存储在表中的关系如下

  UID      FriendID
 ------    --------
 user1      user2
 user1      user3
 user2      user1

但是在这里,我面临两个选择:

  1. 典型情况下,在那里我会同时存储user1 -> user2user2->user1 。 这将需要更多的空间,但(至少在我的头)需要的只是一个传过来的行显示特定用户的朋友。
  2. 另一个选择是将任user1->user2 OR user2->user1 ,每当我想找到的所有的朋友user1 ,我将查询表上的两列,将找到用户的朋友。 这将需要一半的空间,但(再次,至少在我的头上)两倍的时间量。

首先,是我的推理合适? 如果是的话,是没有办法,我差点忘(在缩放/吞吐量或任何方面的)任何瓶颈?

基本上,两者之间有什么取舍,比这里列出的其他。 此外,在行业一个优于其他?

Answer 1:

下面是这两种方法都会在数据库中物理上表示:

让我们来分析这两种方法...

方法1(存储在表的两个方向):

  • PRO:简单的查询。
  • CON:数据可以通过插入/更新被破坏/删除在一个方向。
  • MINOR PRO:不需要额外的限制,以确保友谊不能重复。
  • 进一步的分析需要:
    1. 领带:一个指数涵盖了两个方向,所以你并不需要一个辅助指标。
    2. TIE:存储需求。
    3. TIE:性能。

接近2(存储在表中只有一个方向):

  • CON:更为复杂的查询。
  • PRO:不能腐败被忘记办理相反的方向,因为没有相反方向的数据。
  • MINOR CON:需要CHECK(UID < FriendID)所以相同的友谊永远不能以两种不同的方式来表示,而且按键上(UID, FriendID)可以做自己的工作。
  • 进一步的分析需要:
    1. TIE:两个索引是必要的覆盖查询(在综合指数的两个方向{UID, FriendID}和综合指数{FriendID, UID}
    2. TIE:存储需求。
    3. TIE:性能。

点1是特别感兴趣的。 MySQL的/的InnoDB 总是 簇的数据,二级指标可以在群集表(见“集群的缺点”昂贵的这篇文章 ),所以它可能看起来好像在方法上2次指数将吃了较少的行的所有优点。 然而 ,二次索引包含准确相同的字段作为主(仅在以相反的顺序),所以有在该特定情况下,没有存储开销。 也没有指针表堆(因为没有桌子堆),因此它可能是更便宜的存储明智的,正常的基于堆的指数。 并假设该查询覆盖有索引,不会有一个双查找通常与一个簇表或者是二级索引相关联。 所以,这基本上是一个连接(均未方法1也不方法2具有显著优势)。

点2是有关第1点:不要紧是否我们将有N个值的B树或两个B-树中,每个与N / 2的值。 所以这也是一个领带:这两种方法都会使用,占用存储的大致相同量。

同样的道理也适用于3点 :我们是否寻找一个更大的B-Tree或2级较小的,并没有太大的差别,所以这也是一个平局。

所以,对于稳健性,尽管有些丑陋查询,并需要额外的CHECK ,我会用这种方法去2。



Answer 2:

存储价格相对便宜,这些天,所以我不会担心,因为这一点。

什么会关心我的是,你现在必须清理你的两倍存储信息。 所以,如果你“取消关注”的人,你必须删除2条,不只是一个。

其他考虑因素是搜索和索引。 有可能是散列的用户ID的组合来检查脑干的优势,只要你遵循洽约定(像往常一样散列之前更高的ID追加到更低)。

所以,现在你有其他的可能性。 您是否有兴趣在查询2个用户之间的关系? 或者是更重要的是看一个用户的属性?

这是什么系统将做什么顾虑。 看看像DDD(领域驱动设计)和CQRS(命令查询责任隔离)科目来看看如何瓜分你的应用程序,所以每个区域中可能最简单的方法来实现。 这会给你的渠道进行微调,后来不优化运行到复杂的问题。



Answer 3:

尽管在方案1和方案2之间选择茨尔Dimitrijevic的选择,你应该考虑这个问题:

就是你想设计对称的或不对称的关系?

例如(坏的榜样,但仍说明了我的观点),如果你只是想知道,这两个用户是否为家人或朋友,那么该链接是对称的。 如果一个用户是其他的家庭成员,则反是真实的。 方法2可能会被考虑。

但是如果你想喜欢什么类型的家庭更具体的信息,一个人到另一个(是他们的父亲,儿子,叔父?),那么它变得不对称。 如果A是B的父亲,则B是A的儿子/女儿。 方法1可能成为必要。



文章来源: How to store bidirectional relationships in a RDBMS like MySQL?