Rails 4 Eager load limit子查询

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

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

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

 Category.includes(:posts).all 

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

来自Rails文档

如果您急切地使用指定的: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子句添加到post查询,它将返回总共 10个post而不是每个类别10个post,如您所料。

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

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

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