【问题标题】:What's the difference between "includes" and "joins" in ActiveRecord query?ActiveRecord 查询中的“includes”和“joins”有什么区别?
【发布时间】:2011-02-01 10:27:48
【问题描述】:

ActiveRecord 查询中的“includes”和“joins”有什么区别?谁能用以下两个关联模型向我解释一下?

class Car < ActiveRecord::Base
  belongs_to :store
end

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

【问题讨论】:

    标签: ruby-on-rails ruby-on-rails-3


    【解决方案1】:
    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 非常有用。

    【讨论】:

      【解决方案2】:

      我建议您阅读他们在Rails Guides 中的部分以获取更多信息。

      【讨论】:

        【解决方案3】:

        :joins 返回只读对象,:includes 不返回

        :joins 使用内连接,:includes 使用外连接。

        :includes 的主要原因是急切加载,以避免使用单独的查询加载每个对象的属性的 N+1 问题。

        【讨论】:

          【解决方案4】:

          Joins 只会加入表格并返回选定的字段。如果您在连接查询结果上调用关联,它将再次触发数据库查询

          Include 将预先加载包含的关联并将它们添加到内存中。包含加载所有包含的表属性。如果您在包含查询结果上调用关联,它不会触发任何查询

          【讨论】:

            【解决方案5】:

            TL;博士

            加入:

            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 是 JOINS 的 ActiveRecord 版本,即 SQL 请求。

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

              所以在所见的背后是隐含的INNER JOIN。因此,它确实会返回所有拥有汽车的商店(因为inner_joinleft_outer_join 会有不同的行为)。查看更多here

              :includes 不是查询命令。它解决了eager_loading Car 模型在 Store 模型上的 n+1 查询问题。查看更多eager_loadinghere

              stores = Store.includes(:car)
              

              将因此返回所有商店,并允许在不触发新查询的情况下执行stores.first.car

              【讨论】:

                【解决方案7】:

                Join:它使用延迟加载并执行内部连接。 join 简单地将两个表加在一起

                包含:包含使用预先加载并执行左外连接,包含还可以防止 N+1 查询。

                【讨论】:

                • join 的解释不正确。这不是延迟加载,而是在这两个表之间建立 SQL 连接。您可以将联接策略修改为内部或左侧等。此外,includes 不进行联接,它会为每个关联执行另一个查询以获取关联关系,从而避免每个关联执行 1 个查询或延迟加载时出现 1+N 问题。
                猜你喜欢
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2021-10-02
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                相关资源
                最近更新 更多