我将通过观看一些教程来回顾刷新我的Rails知识,并且我遇到了教程rails app在includes()
上使用index
的地方。
def index
@books = Book.all
end
vs
def index
@books = Book.includes(:author, :genre)
end
作为旁注,预订belongs_to
作者和流派。作者has_many
书籍和流派也是has_many
本书。
使用all
时,刷新页面时看起来像这样:
Rendering books/index.html.erb within layouts/application
Book Load (1.4ms) SELECT "books".* FROM "books"
Author Load (0.3ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
Genre Load (0.3ms) SELECT "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
Author Load (0.4ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
Genre Load (0.3ms) SELECT "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
CACHE (0.0ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
CACHE (0.0ms) SELECT "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT $2 [["id", 3], ["LIMIT", 1]]
CACHE (0.0ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" = $1 LIMIT $2 [["id", 1], ["LIMIT", 1]]
CACHE (0.0ms) SELECT "genres".* FROM "genres" WHERE "genres"."id" = $1 LIMIT $2 [["id", 2], ["LIMIT", 1]]
使用includes
时,当我重新加载页面时显示:
Rendering books/index.html.erb within layouts/application
Book Load (0.4ms) SELECT "books".* FROM "books"
Author Load (0.5ms) SELECT "authors".* FROM "authors" WHERE "authors"."id" IN (2, 1)
Genre Load (0.4ms) SELECT "genres".* FROM "genres" WHERE "genres"."id" IN (2, 3)
我认为这包括远远超过所有因素,因为它击中了整个模型数据库。
我的问题是,为什么人们仍然使用all
?为什么不彻底根除all
并从现在开始使用包含?有什么情况我宁愿全部使用而不使用包含?我正在使用Rails 5.0.1。
答案 0 :(得分:0)
让我谈谈includes
。
假设您需要获取前五个帖子的用户名。您可以快速撰写下面的查询并享受您的周末。
posts = Post.limit(5)
posts.each do |post|
puts post.user.name
end
好。但是让我们看一下查询
Post Load (0.5ms) SELECT `posts`.* FROM `posts` LIMIT 5
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 2 LIMIT 1
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` = 1 LIMIT 1
1 query
为每个帖子提取所有posts
和1 query
以获取users
,结果总共为6 queries
。查看下面的解决方案,它只是在2 queries
:
posts = Post.includes(:user).limit(5)
posts.each do |post|
puts post.user.name
end
#####
Post Load (0.3ms) SELECT `posts`.* FROM `posts` LIMIT 5
User Load (0.3ms) SELECT `users`.* FROM `users` WHERE `users`.`id` IN (1, 2)
有一点不同。将includes(:posts)
添加到您的查询中,问题就解决了。快速,美观,轻松。
但是,如果没有正确理解,请不要在查询中添加includes
。将includes
与joins
一起使用可能会导致交叉连接,具体取决于具体情况,在大多数情况下您不需要这样做。
如果您想为所包含的模型添加条件,则必须明确引用它们。例如:
User.includes(:posts).where('posts.name = ?', 'example')
会抛出错误,但这会有效:
User.includes(:posts).where('posts.name = ?', 'example').references(:posts)
请注意,includes
适用于association names
而references
需要the actual table name
。