2

这个问题可能有点具体,但我认为从一般 pov 来看也很有趣。

在 Rails App 中,用户可以订阅其他用户。当我显示用户列表时,我必须检查当前用户是否订阅了列表中的用户。如果他订阅了,我会显示取消订阅按钮,反之亦然。

因为整个事情取决于当前用户,所以我不能使用急切加载。因此,当我在列表中显示 20 个用户时,我在 DB 上生成了 20 个额外的命中,这在我看来是不好的做法。

我正在考虑解决这个问题的好方法。到目前为止,我想出的最佳解决方案是在登录期间加载 current_user 在会话中订阅的用户的 id,然后检查每个 user.id 与会话中的 id。但是,当用户订阅了很多人时,这可能会导致其他问题。此外,我不确定这是否是加载所有订阅的最佳方式,即使用户在此会话期间可能永远不会查看用户列表。

我想到的下一个最好的事情是做同样的事情,但不是在登录期间,而是在加载用户列表时。

你怎么看?

4

2 回答 2

4

您绝对应该开始使用缓存系统。您至少可以遵循 3 种方法。您还可以将它们组合起来以提高效率。

数据库缓存

创建一个关系表来保存用户和订阅者之间的 ID 关系,这样您就不需要即时计算它们。

模型缓存

可以缓存昂贵的查询。

def find_subscribers
  Rails.cache.fetch("find_subscribers_#{current_user}") do
    # run the query
  end
end

查看缓存

您还可以缓存视图片段以防止昂贵的详细说明。

您可能想从以下内容开始:

编辑:

你的查询可以被优化。

ActiveRecord::Base.connection.execute("SELECT count(*) as c FROM subscribers_users WHERE user_id = #{other_user.id} AND subscriber_id = #{self.id}") 

可以变成

counters = SubscribersUser.count(:conditions => { :subscriber_id => self.id }, :group => "user_id")

该查询将返回一个哈希,其中键是 user_id,值是计数的结果。然后,您可以迭代哈希而不是对视图中的任何记录运行查询。

于 2009-06-26T10:27:52.767 回答
2

如果允许您使用急切加载,则没有禁止重新加载当前用户的规则:

用户 = User.find(current_user.id, :include => :subscribers)

如果这是一个简单的 has_many 关系,那么它只有 2 个 SQL 语句。

现在您可以迭代 user.subscribers 而不会产生另一个数据库命中。

于 2009-06-26T17:37:05.933 回答