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

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

В чем разница между включает "и" присоединяется "в запросе ActiveRecord? Может ли кто-нибудь объяснить мне следующие две связанные модели?

class Car < ActiveRecord::Base
  belongs_to :store
end

class Store < ActiveRecord::Base
  belongs_to :owner
  has_one :car
end
4b9b3361

Ответ 1

:joins объединяет таблицы вместе в sql, :includes загружает ассоциации, чтобы избежать проблемы n + 1 (где выполняется один запрос для извлечения записи, а затем по одной для каждой загружаемой ассоциации).

Я предлагаю вам прочитать их разделы в Rails Guides, чтобы получить дополнительную информацию.

Ответ 2

stores = Store.joins(:car)

Это вернет все магазины, для которых есть автомобиль. stores[0].car приведет к другому запросу.

stores = Store.includes(:car)

Это вернет все магазины, автомобиль или автомобиль. stores[0].car не приведет к другому запросу.

stores = Store.includes(:car).joins(:car)

Это вернет все магазины с автомобилем. stores[0].car не приведет к другому запросу. Я бы не рекомендовал это для отношений has_many, но отлично работает для has_one.

Ответ 3

: join возвращает объекты только для чтения, включает:

: join использует внутреннее соединение: включает в себя использование внешнего соединения.

Основная причина: включает в себя интенсивную загрузку, чтобы избежать проблемы загрузки N + 1 в атрибутах каждого объекта с помощью отдельного запроса.

Ответ 4

Объединения будут просто объединять таблицы и возвращать выбранные поля. если вы вызовете ассоциации для результата запроса объединений, он снова запустит запросы к базе данных.

Включить будет стремиться загрузить включенные ассоциации и добавить их в память. Включить загружает все включенные атрибуты таблиц. Если вы вызываете ассоциации на результат запроса включения, он не будет запускать какие-либо запросы

Вы можете найти подробное объяснение с примерами в этой моей статье: Советы и рекомендации по ассоциациям активной записи.

Ответ 5

TL; DR

Соединения:

a.joins(:b).to_sql
=> "SELECT \"a\".* FROM \"a\" INNER JOIN \"b\" ON \"b\".\"id\" = \"a\".\"b_id\""

Включает:

a.includes(:b).to_sql
=> "SELECT \"a\".* FROM \"a\"

И

a.includes(:b).joins(:b).to_sql
=> "SELECT \"a\".\"id\" AS t0_r0, \"a\".\"a_field_1\" AS t0_r1, \"a\".\"a_field_2\" AS t0_r2, \"a\".\"a_field_3\" AS t0_r3, \"b\".\"a_field_1\" AS t1_r1, \"b\".\"a_field_2\" AS t1_r2, \"b\".\"a_field_3\" AS t1_r3 FROM \"a\" INNER JOIN \"b\" ON \"b\".\"id\" = \"a\".\"plan_id\""

Ответ 6

:joins является версией ActiveRecord JOINS, запроса SQL.

Store.joins(:car).to_sql
=> SELECT stores.* FROM stores INNER JOIN cars ON cars.store_id = categories.id

Итак, за увиденным это скрытое INNER JOIN. Таким образом, он действительно вернет все магазины, в которых есть автомобиль (из-за inner_join, left_outer_join имел бы другое поведение). Подробнее здесь.

Принимая во внимание, что :includes не является командой запроса. Это решает проблему запроса n + 1 от eager_loading модели Автомобиля на модели Магазина. Еще один eager_loading здесь.

stores = Store.includes(:car)
Таким образом,

вернет все хранилища и позволит выполнить stores.first.car без запуска нового запроса.