2015-04-22 1 views
2

Есть ли способ избежать проблемы n + 1 при активной загрузке, а также применить ограничение к подзапросу? Я хочу, чтобы избежать многих SQL запросов, как это:Rails 4 Поддержанный подзапрос ограничения нагрузки

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

Но я также хочу, чтобы получить только 10 сообщений в каждой категории, поэтому стандартный жадную загрузку, которая получает все сообщения, не хватает:

Category.includes(:posts).all 

Каков наилучший способ решить эту проблему? Является ли N + 1 единственным способом ограничить количество должностей в каждой категории?

+0

http://stackoverflow.com/a/26251892/525478 –

ответ

0

От Rails docs

Если вы готовы нагрузки ассоциации с Оговаривается: вариант лимита, то он будет проигнорирован, возвращая все связанные объекты

Так дано определение следующая модель

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. Приветствия.