Подтвердить что ты не робот

Какая разница между "включает" и "предварительную загрузку" в запросе ActiveRecord?

Я пытаюсь найти сравнение include() и preload() для объектов ActiveRecord. Может ли кто-нибудь объяснить разницу?

4b9b3361

Ответ 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) показана здесь". Таким образом, разница в том, что включает в себя только НЕ устаревшие.