代码之家  ›  专栏  ›  技术社区  ›  Rob Cameron

轨道:包含vs:连接

  •  328
  • Rob Cameron  · 技术社区  · 15 年前

    所以你知道你将要使用的相关记录的福音就是 :include 因为您将获得一个连接并避免一大堆额外的查询:

    Post.all(:include => :comments)
    

    但是,当您查看日志时,没有发生连接:

    Post Load (3.7ms)   SELECT * FROM "posts"
    Comment Load (0.2ms)   SELECT "comments.*" FROM "comments" 
                           WHERE ("comments".post_id IN (1,2,3,4)) 
                           ORDER BY created_at asc) 
    

    信息技术 选择快捷方式,因为它一次提取所有注释,但它仍然不是联接(所有文档似乎都这么说)。我能加入的唯一方法就是使用 :joins :包括 :

    Post.all(:joins => :comments)
    

    Post Load (6.0ms)  SELECT "posts".* FROM "posts" 
                       INNER JOIN "comments" ON "posts".id = "comments".post_id
    

    没有像广告宣传的那样工作。

    也许是Rails

    8 回复  |  直到 10 年前
        1
  •  181
  •   pjam    10 年前

    看来 :include Rails 2.1更改了功能。Rails过去在所有情况下都进行连接,但出于性能原因,它在某些情况下被更改为使用多个查询。 This blog post 作者Fabio Akita提供了一些关于这一变化的好信息(请参阅标题为“优化加载”的部分)。

        2
  •  105
  •   Cody Gray    6 年前

    .joins

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

        3
  •  77
  •   holden    15 年前

    例如,如果您有一个满是注释的表,并且使用a:joins=>用户为了排序等目的而拉入所有用户信息,这将很好地工作,并且花费的时间少于:include,但如果您希望显示注释以及用户名、电子邮件等。要使用:joins获取信息,它必须为其获取的每个用户进行单独的SQL查询,而如果您使用:包含此信息即可使用。

    很好的例子:

    http://railscasts.com/episodes/181-include-vs-joins

        4
  •  60
  •   Aaditi Jain    10 年前

    我最近读了更多关于两者区别的文章 :joins :includes 在轨道上。以下是我理解的解释(举例说明:)

    考虑一下这种情况:

    • 一个用户有许多评论,并且一条评论属于一个用户。

    • 用户模型具有以下属性:名称(字符串)、年龄(整数)。注释模型具有以下属性:内容、用户id。对于注释,用户id可以为空。

    加入:

    :joins执行 在两张桌子之间。因此

    Comment.joins(:user)
    
    #=> <ActiveRecord::Relation [#<Comment id: 1, content: "Hi I am Aaditi.This is my first   comment!", user_id: 1, created_at: "2014-11-12 18:29:24", updated_at: "2014-11-12 18:29:24">, 
         #<Comment id: 2, content: "Hi I am Ankita.This is my first comment!", user_id: 2, created_at: "2014-11-12 18:29:29", updated_at: "2014-11-12 18:29:29">,    
         #<Comment id: 3, content: "Hi I am John.This is my first comment!", user_id: 3, created_at: "2014-11-12 18:30:25", updated_at: "2014-11-12 18:30:25">]>
    

    将获得 user_id(注释表)等于user.id(用户表)的所有记录。

    Comment.joins(:user).where("comments.user_id is null")
    
    #=> <ActiveRecord::Relation []>
    

    您将得到一个空数组,如图所示。

    此外,联接不会在内存中加载联接表。因此,如果你这样做

    comment_1 = Comment.joins(:user).first
    
    comment_1.user.age
    #=>←[1m←[36mUser Load (0.0ms)←[0m  ←[1mSELECT "users".* FROM "users" WHERE "users"."id" = ? ORDER BY "users"."id" ASC LIMIT 1←[0m  [["id", 1]]
    #=> 24
    

    如你所见, comment_1.user.age 将在后台再次启动数据库查询以获取结果

    :包括执行 在两张桌子之间。因此

    Comment.includes(:user)
    
    #=><ActiveRecord::Relation [#<Comment id: 1, content: "Hi I am Aaditi.This is my first comment!", user_id: 1, created_at: "2014-11-12 18:29:24", updated_at: "2014-11-12 18:29:24">,
       #<Comment id: 2, content: "Hi I am Ankita.This is my first comment!", user_id: 2, created_at: "2014-11-12 18:29:29", updated_at: "2014-11-12 18:29:29">,
       #<Comment id: 3, content: "Hi I am John.This is my first comment!", user_id: 3, created_at: "2014-11-12 18:30:25", updated_at: "2014-11-12 18:30:25">,    
       #<Comment id: 4, content: "Hi This is an anonymous comment!", user_id: nil, created_at: "2014-11-12 18:31:02", updated_at: "2014-11-12 18:31:02">]>
    

    将导致 包含注释表中所有记录的联接表。 因此,如果你这样做

    Comment.includes(:user).where("comment.user_id is null")
    #=> #<ActiveRecord::Relation [#<Comment id: 4, content: "Hi This is an anonymous comment!", user_id: nil, created_at: "2014-11-12 18:31:02", updated_at: "2014-11-12 18:31:02">]>
    

    它将获取comments.user_id为nil的记录,如图所示。

    此外,include在内存中加载这两个表。因此,如果你这样做

    comment_1 = Comment.includes(:user).first
    
    comment_1.user.age
    #=> 24
    

    正如您所注意到的,comment_1.user.age只需从内存加载结果,而无需在后台启动数据库查询。

        5
  •  55
  •   Brian Maltzan    14 年前

    当你加入评论时,你要求的是有评论的帖子——默认情况下是内部连接。 当你加入评论时,你要求的是所有帖子——一个外部连接。

        6
  •  12
  •   Kevin Choubacha    9 年前

    tl;博士

    -用于有条件地选择记录。

    包括 -对结果集的每个成员使用关联时。

    联接用于过滤来自数据库的结果集。您可以使用它在表上执行设置操作。可以将其视为执行集合论的where子句。

    Post.joins(:comments)

    Post.where('id in (select post_id from comments)')

    但若有多条评论,你们会得到重复的帖子和连接。但每个帖子都会有评论。您可以使用以下方法更正此问题:

    Post.joins(:comments).count
    => 10
    Post.joins(:comments).distinct.count
    => 2
    

    includes 方法将简单地确保在引用关系时没有额外的数据库查询(这样我们就不会进行n+1查询)

    Post.includes(:comments).count
    => 4 # includes posts without comments so the count might be higher.
    

    寓意是,使用 joins 当您要执行条件集操作并使用 包括

        7
  •  4
  •   user3412661 user3412661    11 年前

    .joins用作数据库联接,它联接两个或多个表,并从后端(数据库)获取所选数据。

        8
  •  0
  •   marc_s    9 年前

    “joins”仅用于连接表,当您在连接上调用关联时,它将再次触发查询(这意味着将触发许多查询)

    lets suppose you have tow model, User and Organisation
    User has_many organisations
    suppose you have 10 organisation for a user 
    @records= User.joins(:organisations).where("organisations.user_id = 1")
    QUERY will be 
     select * from users INNER JOIN organisations ON organisations.user_id = users.id where organisations.user_id = 1
    
    it will return all records of organisation related to user
    and @records.map{|u|u.organisation.name}
    it run QUERY like 
    select * from organisations where organisations.id = x then time(hwo many organisation you have)
    

    但是

    @记录=用户。包括(:组织)。其中(“organizations.User\u id=1”)

    select * from users INNER JOIN organisations ON organisations.user_id = users.id where organisations.user_id = 1
    and 
    
    
     select * from organisations where organisations.id IN(IDS of organisation(1, to 10)) if 10 organisation
    and when you run this 
    

    @记录.地图{| u | u.organization.name}