我有使用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
答案 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
甚至更好。