【问题标题】:Rails 4 Eager load limit subqueryRails 4急切负载限制子查询
【发布时间】:2015-04-22 17:04:58
【问题描述】:

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

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

但我也希望每个类别只获得 10 个帖子,因此获取所有帖子的标准预加载是不够的:

Category.includes(:posts).all

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

【问题讨论】:

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


【解决方案1】:

来自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).alllimit 选项将被忽略。如果您查看急切加载生成的 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 子句添加到帖子查询中,它将返回total 10 个帖子,不是您可能期望的每个类别的 10 个帖子。

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

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

虽然您将更多模型加载到内存中,但这肯定会提高性能,因为您只对数据库进行 2 次调用,而 n+1 次。干杯。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多