优化有很多记录关联查询

时间:2016-04-13 20:25:44

标签: ruby-on-rails ruby postgresql ruby-on-rails-4 activerecord

我有使用has many构建的此查询。目的是查找没有preview个关联记录的记录,或者是否有这些记录只选择那些将# User has many enrollments # Enrollment belongs to user. users_with_no_courses = User.includes(:enrollments).select {|user| user.enrollments.empty? || user.enrollments.where(preview: false).empty?} 属性设置为true的记录。下面的代码适用于该用例。但是,此查询不能很好地扩展。当我测试数千条记录时,需要几百秒才能完成。如何改进此查询?

controllers

1 个答案:

答案 0 :(得分:2)

首先,确保enrollments.user_id有一个索引。

其次,您可以通过不加载所有注册并在SQL中进行过滤来加快速度:

User.where(<<-EOQ)
  NOT EXISTS (SELECT 1
              FROM   enrollments e
              WHERE  e.user_id = users.id
              AND    NOT e.preview)
EOQ

顺便说一下,我将你的两个条件简化为一个:“没有注册或没有真正的注册”与“没有真正的注册”相同。

如果您愿意,可以将此条件放入scope,以便更可重复使用。

第三,如果要实例化数千个User对象,这仍然会很慢。所以我会考虑分页是否有意义,或find_each如果这是一个离线脚本。或者使用原始SQL来避免所有对象实例。

哦顺便说一下:即使你说includes(:enrollments),这仍然会回到数据库,给你一个n + 1的问题:

user.enrollments.where(preview: false)

这是因为where表示ActiveRecord无法使用已加载的关联。您可以使用select代替where来避免这种情况。但是,首先不加载enrollments甚至更好。