Rails包括vs all?

时间:2018-01-12 20:02:17

标签: ruby-on-rails database

我将通过观看一些教程来回顾刷新我的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。

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为每个帖子提取所有posts1 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。将includesjoins一起使用可能会导致交叉连接,具体取决于具体情况,在大多数情况下您不需要这样做。

如果您想为所包含的模型添加条件,则必须明确引用它们。例如:

User.includes(:posts).where('posts.name = ?', 'example')

会抛出错误,但这会有效:

User.includes(:posts).where('posts.name = ?', 'example').references(:posts)

请注意,includes适用于association namesreferences需要the actual table name