Что такое eager loading в контексте Ruby on Rails?

Предварительная загрузка ассоциаций Active Record, различия includes, preload и eager_load и важная оговорка о count и size.

Короткий ответ

Что ответить на собеседовании

Eager loading ассоциаций заранее загружает связанные записи и помогает избежать N+1 при их последующем использовании. preload использует отдельные запросы, eager_load — LEFT OUTER JOIN, includes выбирает способ в зависимости от запроса. После загрузки коллекции size использует её содержимое, а count без блока обычно выполняет SQL COUNT. Если нужны только количества, лучше рассмотреть групповую агрегацию или counter cache.

Подробный разбор

Ответ с пояснениями

В контексте Active Record eager loading — предварительная загрузка связанных записей. Она помогает устранить N+1: один запрос получает публикации, а последующее обращение к комментариям каждой публикации иначе может вызвать ещё N запросов. Это не то же самое, что eager loading кода приложения при запуске Rails.

Предположим, Post имеет обычную ассоциацию has_many :comments:

Post.includes(:comments).limit(20).each do |post|
  puts post.comments.size
  post.comments.each { |comment| puts comment.id }
end

В таком простом случае Rails обычно выполнит запрос публикаций и отдельный запрос комментариев для выбранных публикаций. Последующий перебор использует уже загруженные объекты.

Стратегии различаются:

  • preload(:comments) загружает ассоциации отдельными запросами.
  • eager_load(:comments) строит загрузку через LEFT OUTER JOIN. Для коллекций это может сильно увеличить количество строк результата SQL.
  • includes(:comments) выбирает между отдельной загрузкой и JOIN в зависимости от структуры запроса, например условий на связанную таблицу. Это не обещание автоматически найти самый дешёвый план.

Семантика методов описана в руководстве Active Record.

Важно не заменять size в примере на count без блока: такой count обычно выполняет SQL-подсчёт и может снова привести к N отдельным запросам даже после загрузки комментариев. size использует коллекцию, если она уже загружена; сам по себе вызов size на незагруженных ассоциациях не гарантирует устранения N+1. Документация CollectionProxy.

Если нужны только количества, загружать все комментарии в память необязательно: рассмотрите групповой COUNT по публикациям либо корректно поддерживаемый counter cache. При выборе решения оценивают не только число запросов, но и объём загруженных данных, время выполнения и расход памяти.

Практика в реальном времени

Подготовьтесь к следующему собеседованию

Interview Boost учитывает вакансию, резюме и технологии и помогает сформулировать ответ прямо во время интервью.

Начать подготовку