Я пытаюсь найти сравнение include() и preload() для объектов ActiveRecord. Может ли кто-нибудь объяснить разницу?
Какая разница между "включает" и "предварительную загрузку" в запросе ActiveRecord?
Ответ 1
У Rails есть 2 способа избежать проблемы n + 1. Один из них заключается в создании большого запроса на основе соединения для привлечения ваших ассоциаций, а другой - создание отдельного запроса для каждой ассоциации.
Когда вы делаете includes
, рельсы решают, какую стратегию использовать для вас. По умолчанию используется отдельный запрос (предварительная загрузка), если он не считает, что вы используете столбцы из ассоциаций в ваших условиях или порядке. Поскольку это работает только с подходом объединения, он использует это вместо этого.
Эвристика Rails иногда ошибочна или у вас может быть определенная причина для предпочтения одного подхода над другим. preload
(и его метод-компаньон eager_load
) позволяет указать, какую стратегию вы хотите использовать рельсы.
Ответ 2
Для подробного понимания см. этот блог.
В шортах:
Предварительная загрузка загружает данные ассоциации в отдельном запросе.
User.preload(:posts).to_a
# => SELECT "users".* FROM "users" SELECT "posts".* FROM "posts" WHERE "posts"."user_id" IN (1)
Включает в себя загрузку данных ассоциации в отдельном запросе, как преднагрузки. Однако это умнее, чем
preload
. Но в некоторых случаях он объединяет запросы.
Как включает умнее?
мы не можем использовать почтовую таблицу, где условие. Следующий запрос приведет к ошибке.
User.preload(:posts).where("posts.desc='ruby is awesome'")
# =>
SQLite3::SQLException: no such column: posts.desc:
SELECT "users".* FROM "users" WHERE (posts.desc='ruby is awesome')
Но мы можем использовать таблицу сообщений, в которой запрос с включает
User.includes(:posts).where('posts.desc = "ruby is awesome"').to_a
# =>
SELECT "users"."id" AS t0_r0, "users"."name" AS t0_r1, "posts"."id" AS t1_r0,
"posts"."title" AS t1_r1,
"posts"."user_id" AS t1_r2, "posts"."desc" AS t1_r3
FROM "users" LEFT OUTER JOIN "posts" ON "posts"."user_id" = "users"."id"
WHERE (posts.desc = "ruby is awesome")
Как вы можете видеть, включает в себя переход от использования двух отдельных запросов к созданию одного LEFT OUTER JOIN для получения данных. И это также применил поставленное условие.
Ответ 3
Как сказал apidoc: "Этот метод устарел или перенесен на последнюю стабильную версию. Последняя существующая версия (v3.0.9) показана здесь". Таким образом, разница в том, что включает в себя только НЕ устаревшие.