我的网站有关注者/关注系统(如推特)。我的困境是创建数据库结构来处理谁跟随谁。
我想到的是创建一个这样的表:
id | user_id | followers | following
1 | 20 | 23,58,84 | 11,156,27
2 | 21 | 72,35,14 | 6,98,44,12
... | ... | ... | ...
基本上,我认为每个用户都会有一行包含他们的关注者和他们关注的用户的列。他们关注的关注者和关注者的用户ID将以逗号分隔。
这是处理它的有效方法吗?如果没有,最好的选择是什么?
答案 0 :(得分:28)
这是最糟糕的做法。这与正常化有关。有2个单独的表。用户和User_Followers。用户将存储用户信息。 User_Followers将是这样的:
id | user_id | follower_id
1 | 20 | 45
2 | 20 | 53
3 | 32 | 20
User_Id和Follower_Id将是引用Users表中Id列的外键。
答案 1 :(得分:7)
到目前为止,有一个比其他答案提出的更好的物理结构:
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表是clustered,因此二级索引的行为与基于堆的表中的行为不同,如果您不了解它,可能会产生意外的开销。拥有代理主键id
只是添加另一个索引,没有充分理由 1 并使{user_id,follower_id}和{follower_id,user_id}上的索引比它们需要的更胖(因为次要集群表中的索引隐式包含PK的副本。
上表中没有surrogate key id
和(假设InnoDB)在物理上由两个B树表示(一个用于主要/群集密钥,一个用于二级索引),这是关于尽可能高效地搜索双向 2 。如果您只需要一个方向,则可以放弃二级索引并转到一个B树。
1 并且每个额外的索引都占用空间,降低了缓存的有效性并影响了INSERT / UPDATE / DELETE性能。
2 从受访者到追随者,反之亦然。
答案 2 :(得分:5)
该表示的一个弱点是每个关系都被编码两次:一次在跟随者的行中,一次在下一个用户的行中,使得维护数据完整性和更新变得更加乏味。
我会为用户创建一个表,为关系创建一个表。关系表看起来像:
id | follower | following
1 | 23 | 20
2 | 58 | 20
3 | 84 | 20
4 | 20 | 11
...
这样添加新关系只是一个插入,删除关系就是删除。汇总计数以确定给定用户拥有多少粉丝也更容易。
答案 3 :(得分:2)
不,你描述的方法有一些问题。
首先,将多个数据点存储为以逗号分隔的字符串存在许多问题。加入很困难(虽然你可以使用like
加入,但会降低性能),搜索难度大,速度慢,无法按照你想要的方式编制索引。
其次,如果你同时存储了一个关注者列表和一个关注人员列表,你就会有冗余数据(A跟随B的事实会出现在两个地方),这既浪费空间,又创建数据失去同步的可能性(如果数据库在B的关注者列表中显示A,但未在A的关注列表中显示B,则数据以难以恢复的方式不一致)
相反,请使用连接表。这是一个单独的表,其中每一行都有一个用户ID和一个跟随者ID。这允许将事物存储在一个位置,允许索引和连接,还允许您向该行添加其他列,例如显示以下关系何时开始。