【问题标题】:What is the proper way to store friendship associations in a mysql DB在 mysql 数据库中存储友谊关联的正确方法是什么
【发布时间】:2012-01-18 13:06:04
【问题描述】:

我想创建一个表格,我的用户可以在其中关联彼此之间的友谊。同时,此表将与我正在尝试处理的各种其他表之间的一对多关系结合使用。

现在我在想这样的事情

member_id、friend_id、活跃、日期

member_id 将是拨打电话的用户的列,friend_id 将是他们尝试联系的朋友的列,活动将是一种切换 0 = 待定,1 = 活动,日期只是一个该特定行上最后一次活动的记录日期。

现在我的困惑是,如果我要查询,我通常会查询 member_id,然后将其余查询基于关联的friend_id,以便将数据相应地显示给合适的人。因此,考虑到这种逻辑,这让我认为每个请求必须有 2 行。一个是请求的 member_id 和插入到表中的请求的friend_id,然后是相反的一个,所以我每次都可以相应地查询。因此,从本质上讲,对于这个特定表请求的每一个动作,它就像双重浸入,我需要做出 2 个类似的动作才能使其工作。 就优化而言,这对我来说毫无意义。所以我的所有问题是处理这种关系数据的正确方法是什么?还是我真的在理智地思考这是一种处理它的方法?

【问题讨论】:

  • 您的第一个模型完美运行。对于第二部分,找到两个方向,这里已经有很多答案了。简短版:构建你的 SELECT 查询有点花哨,你很容易得到两个方向。

标签: mysql database database-design one-to-many


【解决方案1】:

如果友谊总是是相互的,那么您可以选择数据冗余(即两个方向都有一行)以进行更简单的查询,或者学会接受稍微复杂的查询。除非有令人信服的理由,否则我个人会避免数据冗余-您不仅在浪费空间和性能,而且在执行时需要小心-简单的 CHECK 无法引用其他行,具体取决于您的DBMS 触发器可能会限制它对变异表的作用。

确保每个友谊只有一行的简单方法是始终在member_id 中插入较低的值,在friend_id 中插入较高的值(设置约束CHECK (member_id < friend_id) 以强制执行它)。然后,当您查询时,您将在两个方向进行搜索 - 例如,查找给定人的所有朋友(由 person_id 标识)看起来像这样:

SELECT *
FROM
    person
WHERE
    id <> :person_id
    AND (
        id IN (
            SELECT friend_id
            FROM friendship
            WHERE member_id = :person_id
        )
        OR
        id IN (
            SELECT member_id
            FROM friendship
            WHERE friend_id = :person_id
        )
    )

顺便说一句,在这个方案中,您可能希望将 member_idfriend_id 重命名为 friend1_idfriend2_id...

【讨论】:

  • 请注意:在上面的代码中使用 IN 关键字不是一个好主意,因为它没有在 MySQL 中进行优化。在大型表中,它可能会导致结果缓慢。
  • @maliayas 是的,MySQL 倾向于对子查询进行欠优化。在这种特殊情况下这是否是一个实际问题只能通过对实际数据量进行测量来确定。我的直觉是这里不应该存在性能问题,但如果我错了,那么还有其他方法可以表达基本相同的查询,可以回避 MySQL 在这方面的缺陷(例如 JOIN)。
【解决方案2】:

两种看待方式:

WHERE ((friend_id = x AND member_id = y) OR (friend_id = y AND member_id = x))

将允许您通过简单地陈述关系的一侧来进行查询。如果两边都加了,这个方法仍然可以工作,不会导致返回重复的行。

相反,添加关系的双方,以便您的查询包含

WHERE friend_id = x AND member_id = y

不仅使查询更易于编写,而且更易于规划(意味着更好的数据库性能)。

我的投票是后一种选择。

【讨论】:

    【解决方案3】:

    漂亮 - 你的桌子没有问题。

    另外: 我不确定这个基数是“一对多”还是“多对多”:

    http://en.wikipedia.org/wiki/Cardinality_%28data_modeling%29

    问:我要查询我通常会查询 member_id 然后根据 关联friend_id的其余查询以显示数据 根据对的人

    答:坦率地说,我认为查询“会员对朋友”或“朋友对会员”(或任何其他组合 - 例如分享朋友的朋友)没有任何问题。再一次,它看起来不错。

    【讨论】:

      【解决方案4】:

      引入一个辅助表,如:

      users
      user_id, name, ...
      
      friendship
      user_id, friend_id, ....
      
      select u.name as user, u2.name as friend from users u
          inner join friendship f on f.user_id = u.user_id
          inner join users u2 on u2.user_id = f.friend_id
      

      我认为这与您所拥有的非常相似,只是以查询为例。

      【讨论】:

      • 如果添加了关系的双方,则可能出现重复条目​​。
      • 如果您看到列的名称,则并非如此。这是一种单向关系,如果添加双方,两行就有意义。
      • 如果你查询一个用户找到他的朋友,即使他的朋友加了他,你也只会得到一行关系。这取决于您尝试提取的信息的语义。
      猜你喜欢
      • 2013-02-01
      • 2020-01-19
      • 2011-05-29
      • 1970-01-01
      • 2015-03-20
      • 2016-05-31
      • 2020-12-02
      • 2012-02-27
      • 2020-01-25
      相关资源
      最近更新 更多