Rails 4 Eager load limit子查询

时间:2015-04-22 17:04:59

标签: ruby-on-rails ruby-on-rails-4 eager-loading

有没有办法在急切加载时避免n + 1问题并对子查询应用限制? 我想避免这样的大量SQL查询:

Worksheet.Name

但是我也希望每个类别只能获得10个帖子,所以标准的热切加载会获得所有帖子,但这还不够:

Category.all.each do |category|
  category.posts.limit(10)
end

解决此问题的最佳方法是什么? N + 1是限制每个类别的帖子数量的唯一方法吗?

1 个答案:

答案 0 :(得分:0)

来自Rails docs

  

如果您急切加载与指定的:limit选项的关联,它将被忽略,返回所有关联的对象

因此给出了以下模型定义

class Category < ActiveRecord::Base
  has_many :posts
  has_many :included_posts, -> { limit 10 }, class_name: "Post"
end

调用Category.find(1).included_posts将按预期工作,并在查询中应用限制10。但是,如果您尝试执行Category.includes(:included_posts).all,则会忽略limit选项。如果您查看由急切加载生成的SQL,您可以看到为什么会出现这种情况

Category.includes(:posts).all

Category Load (0.2ms)  SELECT "categories".* FROM "categories"
Post Load (0.4ms)  SELECT "posts".* FROM "posts" WHERE "posts"."category_id" IN (1, 2, 3)

如果您在帖子查询中添加了LIMIT子句,则会返回10个帖子的总计,并且每个类别 10个帖子,如您所料

回到你的问题,我会急切加载所有帖子,然后使用first(10)限制加载的集合

categories = Category.includes(:posts).all
categories.first.posts.first(10)

虽然您正在将更多模型加载到内存中,但由于您只对数据库进行2次调用而非n + 1,因此必然会更高效。欢呼声。