首页 > 解决方案 > 避免在 Activerecord 上进行多选

问题描述

我目前有以下代码来查找用户放置的所有评论的唯一 ID。这工作“很好”。但是,对于有很多评论的用户来说,这真的很慢,我试图弄清楚是否有更优雅的方式来处理这个问题,因为它似乎不是最好的解决方案。

  def find_unique_user_grades
    @comments = []
    @environment.users.includes(:comments).map(&:comments).select do |comments|
      comments.select { |comment| @comments.push(comment.id) }
    end
    @comments.uniq!
  end

我希望有人可以帮助我解决这个问题。

标签: ruby

解决方案


您应该总是更喜欢在数据库中执行此操作,而不是在 Ruby 中。您发布的代码users将从数据库中全部加载,然后将原始行数据转换为 ActiveRecord 对象,这(相对)非常昂贵。您不需要任何数据即可加入comments. 然后,您将对每个用户的comments(查询和创建 ActiveRecord 对象)执行相同的操作,并且再次,您不需要任何这些来获取评论id列。

你所追求的(假设我已经正确猜到了你的模式的形状)是一个简单的join后跟一个pluck. 这将运行单个查询并返回单个数字数组,而无需任何在 Ruby 中加载users、创建对象、加载comments、创建对象或迭代的成本。

最后,它还将distinct在数据库中执行查询,它可以利用任何相关索引,而不是uniq在 Ruby 中进行查询。

正确的查询接近于:

 @environment.users.joins(:comments).distinct.pluck('comments.id')

推荐阅读