社交网络应用程序中友谊的最佳数据库架构
Best database architecture for friendships in a social networking application
我在 Rails 的一个社交网站上工作,目前我能想到几种实现友谊的方法(就像 Facebook)。但是由于应用程序的很多功能都将依赖于应用程序的这一部分,所以我有点担心提交一个,然后意识到我可以做得更好,然后进行迁移并更改整个一件一件的事情。
如果你们能建议最好的方法,那就太好了。此外,如果我的 none 个架构足够好,请随意推荐一个新架构
架构 1
一个 table 的友谊有 3 列 -
- user_id(发送请求的用户id)
- friend_id(收到请求的用户id)
- pending(保持状态的布尔值。如果请求被接受则为 false,否则为 true)
获取用户的所有好友
def friends
user_ids = Friendship.where(
'(user_id = :id OR friend_id = :id) AND pending = false',
id: self.id
).pluck(:user_id, :friend_id)
.flatten
.uniq
.reject { |id| id == self.id }
users = User.where(id: user_ids)
end
获取用户收到的所有好友请求 -
def friend_requests
friend_ids = Friendship.where('friend_id = ? AND pending = true', self.id).all
users = User.where(id: friend_ids)
end
我能想到的优点-
- 与其他架构相比,它需要最少的 table 和数据库中的记录。我不确定这是否真的是一个优势,因为我听说 table 中的记录数不会影响性能。如果我错了,请纠正我。
- 只需要几次验证。首先,user_id 在 friend_id 的范围内是唯一的。其次 user_id 不等于 friend_id.
- 干代码。接受朋友请求只需要找到记录并更新一个字段(布尔值 - 待定)。解除好友只需要找到记录并删除它
缺点我能想到的-
- User.friends 和 User.friend_requests 不是可预先加载的,因为它们实际上不是 ActiveRecord 关联。这可能是一个主要的减速点,在长 运行 中,尤其是搜索功能,我想根据一些共同的朋友对结果进行排名。
架构 2
两个 table。一种用于友谊,一种用于朋友请求 -
友谊会像 -
- user_id(好友中其中一位用户的id)
- friend_id(好友中其他用户的id)
好友请求 table 也会像 -
- user_id(好友中其中一位用户的id)
- friend_id(好友中其他用户的id)
获取用户的所有好友 -
has_many :friendships,
class_name: "Friendship",
foreign_key: :user_id,
primary_key: :id
has_many :friends,
through: :friendships,
source: :friend
获取用户的所有好友请求 -
has_many :friend_requests,
class_name: "FriendRequest",
foreign_key: :friend_id,
primary_key: :id
我能想到的优点是 -
- User.friends 和 User.friend_requests 是可预先加载的。这可以提高很多地方的性能,我可以在单个查询中急切加载一群用户的朋友,而不是一遍又一遍地访问数据库并执行 User.friends
我能想到的缺点是 -
- 友谊条目重复。要使 User.friends 关联正常工作,我必须为单个好友创建 2 个条目。
| id | user_id | friend_id |
-----------------------------
| 1 | 15 | 30 |
-----------------------------
| 2 | 30 | 15 |
-----------------------------
- 这将需要复杂的验证,例如:如果第 1 行存在,则验证第 2 行是否存在(在上例中)。还有许多其他人
- 建立友谊会很复杂。这需要
- 删除好友请求条目table
- 在好友中创建2行table
- 我知道这听起来不像是一个真正的缺点,但对我来说,当 creating/deleting 3 个条目相互依赖时,似乎很多地方都可能出错
我猜最后问题归结为 -
数据库中条目数较少(一半)(架构 1)是否比条目较多(架构 2)具有显着优势?
和
一个友谊有 2 个条目有多糟糕? (架构二)
我推荐第二种模式,friend_request
和 friendship
分开 table。虽然这些 table 目前可能持有完全相同的数据,但随着时间的推移,我预计它们会有所不同。
以下是发生这种情况的一些可能方式:-
- 您想允许他们在发送好友请求的同时发送消息 ("Hey, remember me from school")
- 您决定要保留有关好友请求的统计信息,例如发出请求的时间
- 您决定要在数据库中保留被拒绝的好友请求(一旦被拒绝就不允许进一步的请求)
因为它们是不同的东西,所以您应该创建不同的 table 而不是重载单个 table。创建 table.
并不难
是否应该在 table 中放置两行,代表关系的两个方向?这是规范化 vs 性能 的问题。
规范化答案是只包含一行。这个型号:
- 更容易获得 update/insert/delete 因为只需要担心一行
- 查询起来更困难也更慢,因为您需要从两个方向查询
去规范化答案(因为存储了重复的数据)是包括两行:这个模型:
- 更难 update/insert/delete 因为有两行要保持同步
- 查询速度更快,因为您可以只从一个方向查询
我在 Rails 的一个社交网站上工作,目前我能想到几种实现友谊的方法(就像 Facebook)。但是由于应用程序的很多功能都将依赖于应用程序的这一部分,所以我有点担心提交一个,然后意识到我可以做得更好,然后进行迁移并更改整个一件一件的事情。
如果你们能建议最好的方法,那就太好了。此外,如果我的 none 个架构足够好,请随意推荐一个新架构
架构 1
一个 table 的友谊有 3 列 -
- user_id(发送请求的用户id)
- friend_id(收到请求的用户id)
- pending(保持状态的布尔值。如果请求被接受则为 false,否则为 true)
获取用户的所有好友
def friends
user_ids = Friendship.where(
'(user_id = :id OR friend_id = :id) AND pending = false',
id: self.id
).pluck(:user_id, :friend_id)
.flatten
.uniq
.reject { |id| id == self.id }
users = User.where(id: user_ids)
end
获取用户收到的所有好友请求 -
def friend_requests
friend_ids = Friendship.where('friend_id = ? AND pending = true', self.id).all
users = User.where(id: friend_ids)
end
我能想到的优点-
- 与其他架构相比,它需要最少的 table 和数据库中的记录。我不确定这是否真的是一个优势,因为我听说 table 中的记录数不会影响性能。如果我错了,请纠正我。
- 只需要几次验证。首先,user_id 在 friend_id 的范围内是唯一的。其次 user_id 不等于 friend_id.
- 干代码。接受朋友请求只需要找到记录并更新一个字段(布尔值 - 待定)。解除好友只需要找到记录并删除它
缺点我能想到的-
- User.friends 和 User.friend_requests 不是可预先加载的,因为它们实际上不是 ActiveRecord 关联。这可能是一个主要的减速点,在长 运行 中,尤其是搜索功能,我想根据一些共同的朋友对结果进行排名。
架构 2
两个 table。一种用于友谊,一种用于朋友请求 - 友谊会像 -
- user_id(好友中其中一位用户的id)
- friend_id(好友中其他用户的id)
好友请求 table 也会像 -
- user_id(好友中其中一位用户的id)
- friend_id(好友中其他用户的id)
获取用户的所有好友 -
has_many :friendships,
class_name: "Friendship",
foreign_key: :user_id,
primary_key: :id
has_many :friends,
through: :friendships,
source: :friend
获取用户的所有好友请求 -
has_many :friend_requests,
class_name: "FriendRequest",
foreign_key: :friend_id,
primary_key: :id
我能想到的优点是 -
- User.friends 和 User.friend_requests 是可预先加载的。这可以提高很多地方的性能,我可以在单个查询中急切加载一群用户的朋友,而不是一遍又一遍地访问数据库并执行 User.friends
我能想到的缺点是 -
- 友谊条目重复。要使 User.friends 关联正常工作,我必须为单个好友创建 2 个条目。
| id | user_id | friend_id |
-----------------------------
| 1 | 15 | 30 |
-----------------------------
| 2 | 30 | 15 |
-----------------------------
- 这将需要复杂的验证,例如:如果第 1 行存在,则验证第 2 行是否存在(在上例中)。还有许多其他人
- 建立友谊会很复杂。这需要
- 删除好友请求条目table
- 在好友中创建2行table
- 我知道这听起来不像是一个真正的缺点,但对我来说,当 creating/deleting 3 个条目相互依赖时,似乎很多地方都可能出错
我猜最后问题归结为 -
数据库中条目数较少(一半)(架构 1)是否比条目较多(架构 2)具有显着优势?
和
一个友谊有 2 个条目有多糟糕? (架构二)
我推荐第二种模式,friend_request
和 friendship
分开 table。虽然这些 table 目前可能持有完全相同的数据,但随着时间的推移,我预计它们会有所不同。
以下是发生这种情况的一些可能方式:-
- 您想允许他们在发送好友请求的同时发送消息 ("Hey, remember me from school")
- 您决定要保留有关好友请求的统计信息,例如发出请求的时间
- 您决定要在数据库中保留被拒绝的好友请求(一旦被拒绝就不允许进一步的请求)
因为它们是不同的东西,所以您应该创建不同的 table 而不是重载单个 table。创建 table.
并不难是否应该在 table 中放置两行,代表关系的两个方向?这是规范化 vs 性能 的问题。
规范化答案是只包含一行。这个型号:
- 更容易获得 update/insert/delete 因为只需要担心一行
- 查询起来更困难也更慢,因为您需要从两个方向查询
去规范化答案(因为存储了重复的数据)是包括两行:这个模型:
- 更难 update/insert/delete 因为有两行要保持同步
- 查询速度更快,因为您可以只从一个方向查询