Какая разница между "включает" и "присоединяется" в запросе ActiveRecord?
В чем разница между включает "и" присоединяется "в запросе ActiveRecord? Может ли кто-нибудь объяснить мне следующие две связанные модели?
class Car < ActiveRecord::Base
belongs_to :store
end
class Store < ActiveRecord::Base
belongs_to :owner
has_one :car
end
Ответы
Ответ 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
без запуска нового запроса.