【问题标题】:Which method is better to store related data in table(s)哪种方法更好地将相关数据存储在表中
【发布时间】:2013-11-02 04:23:25
【问题描述】:

我有一个关于在数据库中存储数据的简单但重要的问题。
假设一个网站有 100,000 个用户。这些用户可以互相成为朋友。 哪种存储方式比较理想

方法一:

  1. 在 USERS 表中创建一个friends 字段。类型:文本
  2. 保存所有朋友的ID,用,连接他们。示例:用户 1 的朋友:2,3,4,5,6,...
  3. 最差状态:所有用户都是好友,每个用户都有一个FULL TEXT好友字段。所以在php方面,应该用,分隔这个字段,这需要一些过程。

方法B:

  1. 制作一个friendship

    +------+---------------------+  
    | uid  | friend_id           |  
    +------+---------------------+  
    | 1    | 2                   |  
    | 1    | 3                   |    
    | 1    | 4                   |  
    | 1    | 5                   |
    +------+---------------------+ 
    
  2. 正如您在上面看到的,对于用户的每个朋友,我应该在表中插入一个新行。

  3. 最糟糕的状态:所有用户都是朋友,所以表中应该存储 100,000 x 100,000(不确定)行。

这两种方法中哪一种可以?性能和优化。

提前致谢。

【问题讨论】:

  • 方法 A 太可怕了。不要对自己那样做。
  • 方法 A 正在将一个字符串引入您的数据库,而数据库通常不能很好地处理字符串/数组(不能加入它们,很难带出朋友列表......等等) .方法 B 更可取,每个朋友关系 1 行。有趣的是,要读取方法 A 中的数据,您几乎必须将其转换为方法 B 已经存储的数据。

标签: php mysql sql performance optimization


【解决方案1】:

方法B是首选,根据normalization theory

方法A会出现以下问题:

  1. 较慢,因为在大多数情况下,字符串搜索需要更多时间,而整数比较更快。
  2. 维护参照完整性将是一个问题。例如,如果您删除任何用户,该用户是任何用户的朋友,您应该将其从他们的 friend 字段中删除。这将花费大量时间,因为 DBMS 必须执行大量的字符串处理操作。
  3. 在这种情况下构建复杂的查询可能会出现问题。

这只是问题的冰山一角。如果用户表位于数据库模式的中间(因为它经常发生),它将导致整个数据库速度变慢。我的意思是,如果它将链接到许多其他表。

您可以从方法B轻松恢复方法A表示:

SELECT
    `User`.`uid` as `user`,
    GROUP_CONCAT(`Friendship`.`friend_id`) as `friends`
FROM
    `User` LEFT JOIN `Friendship` ON `User`.`uid` = `Friendship`.`uid`
GROUP BY
    `User`.`uid`

但是,从方法A开始,获得方法B表示可能是一项复杂的任务。好好想想吧。

【讨论】:

    【解决方案2】:

    如果需要查询或链接:方法B,没问题。确保将其设为无符号类型并在其上放置索引。 TEXT 字段不会在内存中读取,而是交换到磁盘,它总是很慢,应该避免在非必要时避免。

    【讨论】:

      【解决方案3】:

      选项B是你应该选择的,并放置两个索引,一个用于友谊表的每一列。

      两个表上的所有 CRUD 操作都会更快

      A 要求您通过组合 LIKE 和 OR 运算符来执行搜索,它可能会很慢

      【讨论】:

        【解决方案4】:

        您的方法 B 是正确的方法。它既快速又灵活。

        重要提示:

        • 您应该在 friendship 表中的 2 列组合上创建一个 UNIQUE 索引。这样,您将确保该表中不会出现重复项。此外,在这种情况下,您甚至不需要单独的 Identity 列(除非您出于其他原因需要它) - 复合键本身可以是该表的 PK。
        • 从这 2 列中的每一列创建一个 FOREIGN KEY 到您的 friends 表的 ID 列中。这将有助于确保您系统中的参照完整性。

        我还建议将关系的两侧表示为 2 行,即 1 -> 2 和 2-> 1 应该在不同的行上。这种方法具有更多优势:

        • “查找人员 1 的所有朋友”的逻辑必须只查看第 1 列(而不是两列)
        • 稍后可以添加其他列来显示“友谊状态”之类的内容,这在 2 行中会有所不同,例如“invitation sent”(在 1->2 行)或“invitation received”(在 2->1 行)。

        【讨论】:

          【解决方案5】:

          通常的方法是你的方法B

          在数据库设计中,您尝试为每个字段提供一个信息。与所有朋友一起存储一个巨大的字符串将是不干净和烦人的。此外,每次创建/删除友谊时,您都需要在两个不同的地方更改您的桌子,这也非常糟糕(在维护方面)。 此外,执行整个字符串爆炸、搜索等操作。需要更长的时间然后通过 SQL 搜索表。

          总而言之,方法B是:

          1. 更加干净和规范
          2. 更易于维护
          3. 更快
          4. 更直观。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-08-15
            • 1970-01-01
            • 1970-01-01
            • 2013-12-08
            • 1970-01-01
            相关资源
            最近更新 更多