Rob*_*ron 340 ruby database join ruby-on-rails rails-activerecord
这更像是"为什么这样做的事情"这个问题,而不是"我不知道该怎么做"这个问题......
所以关于拉动你知道你将要使用的相关记录的福音就是使用,:include
因为你将获得一个连接并避免一大堆额外的查询:
Post.all(:include => :comments)
Run Code Online (Sandbox Code Playgroud)
但是,当您查看日志时,没有发生加入:
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)
Run Code Online (Sandbox Code Playgroud)
它正在采取一种捷径,因为它会立即提取所有注释,但它仍然不是连接(这是所有文档似乎都说的).我可以获得连接的唯一方法是使用:joins
而不是:include
:
Post.all(:joins => :comments)
Run Code Online (Sandbox Code Playgroud)
日志显示:
Post Load (6.0ms) SELECT "posts".* FROM "posts"
INNER JOIN "comments" ON "posts".id = "comments".post_id
Run Code Online (Sandbox Code Playgroud)
我错过了什么吗?我有一个有六个关联的应用程序,在一个屏幕上我显示所有这些数据.似乎最好有一个加入查询而不是6个人.我知道在性能方面,进行连接而不是单个查询并不总是更好(事实上,如果你花费时间,看起来上面的两个单独的查询比连接更快),但是在所有文档之后我一直在阅读,我很惊讶地看到:include
不像宣传的那样工作.
也许Rails的是认识到性能问题,并除非在某些情况下,不加入呢?
Pre*_*rem 88
.joins
将只加入表格并带来选定的字段作为回报.如果在连接查询结果上调用关联,它将再次触发数据库查询
:includes
将急切加载包含的关联并将其添加到内存中.:includes
加载所有包含的表属性.如果在包含查询结果上调用关联,则不会触发任何查询
hol*_*den 70
连接和包含之间的区别在于,使用include语句会生成一个更大的SQL查询,将来自其他表的所有属性加载到内存中.
例如,如果你有一个充满注释的表,并且你使用:joins => users来提取所有用户信息以进行排序等,它将正常工作并且花费的时间少于:include,但是你想要显示注释以及用户名,电子邮件等.要使用以下方式获取信息:连接,它必须为其提取的每个用户单独进行SQL查询,而如果您使用:包含此信息已准备就绪,可以使用.
好例子:
http://railscasts.com/episodes/181-include-vs-joins
Aad*_*ain 50
我最近正在阅读有关rails :joins
和:includes
rails 之间差异的更多内容.这是我理解的解释(用例子:))
考虑这种情况:
用户has_many评论和评论belongs_to用户.
User模型具有以下属性:Name(字符串),Age(整数).Comment模型具有以下属性:Content,user_id.对于注释,user_id可以为null.
:join在两个表之间执行内部联接.从而
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">]>
Run Code Online (Sandbox Code Playgroud)
将获取user_id(注释表)等于user.id(users表)的所有记录.因此,如果你这样做
Comment.joins(:user).where("comments.user_id is null")
#=> <ActiveRecord::Relation []>
Run Code Online (Sandbox Code Playgroud)
您将获得一个空数组,如图所示.
此外,连接不会将连接的表加载到内存中.因此,如果你这样做
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
Run Code Online (Sandbox Code Playgroud)
如您所见,comment_1.user.age
将在后台再次触发数据库查询以获取结果
:includes 在两个表之间执行左外连接.从而
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">]>
Run Code Online (Sandbox Code Playgroud)
将生成一个连接表,其中包含评论表中的所有记录.因此,如果你这样做
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">]>
Run Code Online (Sandbox Code Playgroud)
它将获取comments.user_id为零的记录,如图所示.
此外,还包括加载内存中的表.因此,如果你这样做
comment_1 = Comment.includes(:user).first
comment_1.user.age
#=> 24
Run Code Online (Sandbox Code Playgroud)
您可以注意到,comment_1.user.age只是从内存加载结果而不在后台触发数据库查询.
TL;博士
我用两种方式对比它们:
连接 - 用于条件选择记录.
includes - 在结果集的每个成员上使用关联时.
更长的版本
连接旨在过滤来自数据库的结果集.您可以使用它来对表进行设置操作.可以将其视为执行集合论的where子句.
Post.joins(:comments)
是相同的
Post.where('id in (select post_id from comments)')
除非如果有多个注释,您将通过联接返回重复的帖子.但每篇文章都将是一篇有评论的帖子.您可以使用distinct进行更正:
Post.joins(:comments).count
=> 10
Post.joins(:comments).distinct.count
=> 2
Run Code Online (Sandbox Code Playgroud)
在契约中,该includes
方法将简单地确保在引用关系时没有其他数据库查询(这样我们就不会进行n + 1个查询)
Post.includes(:comments).count
=> 4 # includes posts without comments so the count might be higher.
Run Code Online (Sandbox Code Playgroud)
道德是,joins
当你想要进行条件集操作时使用includes
,并在你打算在集合的每个成员上使用关系时使用.
归档时间: |
|
查看次数: |
133527 次 |
最近记录: |