Это связано с вопросом год и изменением назад .
Я привел пример вопроса, который должен работать из коробки, при условии, что у вас есть sqlite3: https://github.com/cairo140/rails-eager-loading-counts-demo
Инструкции по установке (для основной ветки)
git clone git://github.com/cairo140/rails-eager-loading-counts-demo.git
cd rails-eager-loading-counts-demo
rails s
У меня более полная запись в репозитории, но мой общий вопрос такой:
Как я могу заставить Rails активно рассчитывать нагрузку таким образом, чтобы минимизировать количество запросов к базе данных по всем направлениям?
Проблема n+1
возникает всякий раз, когда вы используете #count
в ассоциации, несмотря на то, чтоассоциация через #includes(:associated)
в ActiveRelation.Обходной путь должен использовать #length
, но это работает хорошо только тогда, когда объект, к которому он вызывается, уже загружен, не говоря уже о том, что я подозреваю, что он дублирует что-то, что внутренняя часть Rails уже сделала.Кроме того, проблема с использованием #length
заключается в том, что это приводит к неудачной перегрузке, когда ассоциация не была загружена для начала, и счетчик - это все, что вам нужно.
Из файла readme:
Мы можем избежать этой проблемы, запустив #length в массиве posts (см. Приложение), который уже загружен, но было бы неплохо также иметь доступный счетчик.Мало того, что это более последовательно;он обеспечивает путь доступа, который не обязательно требует загрузки сообщений.Например, если у вас есть частичное, которое отображает счет независимо от того, что, но половину времени, частичное вызывается с загруженными сообщениями, а половину - без, вы сталкиваетесь со следующим сценарием:
- Использование
#count
- n
COUNT
запросов в стиле, когда сообщения уже загружены - n
COUNT
запросов в стиле, когда сообщения еще не загружены
- Использование
#length
- Ноль дополнительных запросов, когда сообщения уже загружены
- n
*
Стиль запросов, когда сообщения еще не загружены
Между этими двумя вариантами нет доминирующего варианта.Но было бы неплохо изменить #count, чтобы отложить до #length или получить доступ к длине, которая каким-то другим образом хранится за кулисами, чтобы у нас был следующий сценарий:
- Использование пересмотренного
#count
- Ноль дополнительных запросов, когда сообщения уже загружены
- n
COUNT
Стиль запросов, когда сообщения еще не загружены
Так какой правильный подход здесь?Есть что-то, что я упустил (очень, очень вероятно)?