3

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

方法一:

  1. friends在 USERS 表中创建一个字段。类型:文本
  2. 将所有朋友的 ID 保存在其中,并用,. 例如:用户 1 的朋友:2,3,4,5,6,...
  3. 最糟糕的状态:所有用户都是朋友,每个用户都有一个全文朋友字段。所以在 php 方面,应该用,分隔符分隔这个字段,这需要一些过程。

方法B:

  1. 做一张friendship桌子

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

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

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

提前致谢。

4

5 回答 5

1

根据归一化理论,方法 B是首选。

方法A会有以下问题:

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

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

您可以从Method B轻松恢复Method 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`

但是,从Method A开始获取Method B表示可能是一项复杂的任务。考虑一下。

于 2013-10-23T18:20:58.017 回答
1

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

于 2013-10-23T18:22:08.210 回答
1

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

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

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

于 2013-10-23T18:23:21.237 回答
1

通常的方法是你的方法 B

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

所以总而言之,方法B是:

  1. 更干净和规范
  2. 更容易维护
  3. 快点
  4. 更直观。
于 2013-10-23T18:24:56.957 回答
1

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

重要笔记:

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

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

  • 您“查找第 1 个人的所有朋友”的逻辑必须只查看第 1 列(而不是两列)
  • 稍后可以添加其他列以显示诸如“友谊状态”之类的内容,这些内容在 2 行中会有所不同,例如“已发送邀请”(在 1->2 行中)或“收到邀请”(在 2->1 行中) )。
于 2013-10-23T18:48:17.423 回答