关注者/关注者数据库结构


Followers/following database structure

我的网站有一个关注者/关注系统(如Twitter的)。我的困境是创建数据库结构来处理谁在关注谁。

我想出的是创建一个这样的表:

 id  |  user_id  |  followers |  following
  1  |    20     |  23,58,84  |  11,156,27
  2  |    21     |  72,35,14  |  6,98,44,12
 ... |   ...     |    ...     |     ...

基本上,我认为每个用户都会有一行列,用于他们的关注者和他们关注的用户。关注者和他们关注的人的用户 ID 将用逗号分隔。

这是一种有效的处理方式吗?如果没有,最好的选择是什么?

这是

最糟糕的方法。这是反对正常化的。有 2 个单独的表。用户和User_Followers。用户将存储用户信息。User_Followers会是这样的:

id | user_id | follower_id
1  | 20      | 45
2  | 20      | 53
3  | 32      | 20

User_Id 和 Follower_Id 将是引用"用户"表中 Id 列的外键。

到目前为止,

有一个比其他答案提出的更好的物理结构:

CREATE TABLE follower (
    user_id INT, -- References user.
    follower_id INT,  -- References user.
    PRIMARY KEY (user_id, follower_id),
    UNIQUE INDEX (follower_id, user_id)
);

InnoDB 表是集群的,因此二级索引的行为与基于堆的表中的行为不同,如果您没有意识到这一点,可能会产生意外的开销。使用代理主键id只是无缘无故地添加另一个索引1,并使 {user_id、follower_id} 和 {follower_id 上的索引user_id比它们需要的更胖(因为聚集表中的二级索引隐式包含 PK 的副本)。

上表没有代理键id并且(假设InnoDB)由两个B树(一个用于主/聚类键,一个用于二级索引)物理表示,这与两个方向搜索的效率一样高2。如果你只需要一个方向,你可以放弃二级索引,只到一个B树。

顺便说一句,您的所作所为违反了原子性原则,因此违反了 1NF。


1 每增加一个索引都会占用空间,降低缓存效率并影响插入/更新/删除性能。

2 从追随者到追随者,反之亦然。

这种表示的一个弱点是每个关系被编码两次:一次在行中用于关注者,一次在行中用于下一个用户,这使得维护数据完整性变得更加困难,并且更新很乏味。

我会为用户制作一个表,为关系制作一个表。 关系表如下所示:

id | follower | following
1  | 23       | 20
2  | 58       | 20
3  | 84       | 20
4  | 20       | 11
...

这样,添加新关系只是插入,删除关系就是删除。 汇总计数以确定给定用户有多少关注者也容易得多。

不,您描述的方法存在一些问题。

首先,将多个数据点存储为逗号分隔的字符串存在许多问题。 很难加入(虽然您可以使用like加入会降低性能),搜索起来既困难又缓慢,并且无法按照您想要的方式编制索引。

其次,如果您同时存储关注者列表和关注人员列表,则您有冗余数据(A 关注 B 的事实将显示在两个位置),这既浪费空间,也会产生数据不同步的可能性(如果数据库在 B 的关注者列表中显示 A, 但在 A 的以下列表中没有显示 B,则数据不一致,很难从中恢复)。

请改用联接表。 这是一个单独的表,其中每行都有一个用户 ID 和一个关注者 ID。 这允许将内容存储在一个位置,允许索引和联接,还允许您向该行添加其他列,例如显示以下关系的开始时间。