【问题标题】:Rails: How do I minimize DB hits here? Eager loading isn't applicableRails:如何在此处最小化 DB 命中?急切加载不适用
【发布时间】:2009-06-26 09:55:46
【问题描述】:

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

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

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

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

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

你怎么看?

【问题讨论】:

    标签: ruby-on-rails performance session caching eager-loading


    【解决方案1】:

    您绝对应该开始使用缓存系统。 您至少可以遵循 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,值是计数的结果。然后您可以迭代哈希而不是对视图中的任何记录运行查询。

    【讨论】:

    • 谢谢,我已经有一个关系表,到目前为止我的查询并不昂贵。它只是执行了很多: ActiveRecord::Base.connection.execute("SELECT count(*) as c FROM subscribers_users WHERE user_id = #{other_user.id} AND subscriber_id = #{self.id}") 但据我所知你我应该用一个查询来获取所有订阅者并缓存结果。对吗?
    • 我在原始回复中添加了更多细节。
    【解决方案2】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-09
      • 2010-10-25
      • 2015-08-05
      • 1970-01-01
      • 2021-10-08
      • 1970-01-01
      相关资源
      最近更新 更多