Rails 4 预加载限制子查询
Rails 4 Eager load limit subquery
有没有办法避免急切加载时的 n+1 问题,同时对子查询应用限制?
我想避免很多这样的 sql 查询:
Category.all.each do |category|
category.posts.limit(10)
end
但我还希望每个类别只获得 10 个帖子,因此获取所有帖子的标准预先加载是不够的:
Category.includes(:posts).all
解决这个问题的最佳方法是什么? N+1 是限制每个类别帖子数量的唯一方法吗?
If you eager load an association with a specified :limit option, it will be ignored, returning all the associated objects
所以给定以下模型定义
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
选项将被忽略。如果您查看由 eager load
生成的 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
子句添加到帖子查询中,它将 return 总共 10 个帖子并且 不会 如您所料,每个类别 10 个帖子。
回到你的问题,我会急于加载所有帖子,然后使用 first(10)
限制加载的集合
categories = Category.includes(:posts).all
categories.first.posts.first(10)
虽然您正在将更多模型加载到内存中,但这必然会提高性能,因为您只对数据库进行 2 次调用,而不是 n+1 次。干杯。
有没有办法避免急切加载时的 n+1 问题,同时对子查询应用限制? 我想避免很多这样的 sql 查询:
Category.all.each do |category|
category.posts.limit(10)
end
但我还希望每个类别只获得 10 个帖子,因此获取所有帖子的标准预先加载是不够的:
Category.includes(:posts).all
解决这个问题的最佳方法是什么? N+1 是限制每个类别帖子数量的唯一方法吗?
If you eager load an association with a specified :limit option, it will be ignored, returning all the associated objects
所以给定以下模型定义
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
选项将被忽略。如果您查看由 eager load
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
子句添加到帖子查询中,它将 return 总共 10 个帖子并且 不会 如您所料,每个类别 10 个帖子。
回到你的问题,我会急于加载所有帖子,然后使用 first(10)
categories = Category.includes(:posts).all
categories.first.posts.first(10)
虽然您正在将更多模型加载到内存中,但这必然会提高性能,因为您只对数据库进行 2 次调用,而不是 n+1 次。干杯。