由于rails 4 和之前的版本在贪婪加载有所不同,所以需要详细的介绍
资料来源:http://guides.rubyonrails.org/active_record_querying.html#eager-loading-associations

Eager loading is the mechanism for loading the associated records of the objects returned by Model.find using as few queries as possible.

N + 1 queries problem

Consider the following code, which finds 10 clients and prints their postcodes:

clients = Client.limit(10)

clients.each do |client|
  puts client.address.postcode
end

This code looks fine at the first sight. But the problem lies within the total number of queries executed. The above code executes 1 (to find 10 clients) + 10 (one per each client to load the address) = 11 queries in total.

Solution to N + 1 queries problem

Active Record lets you specify in advance all the associations that are going to be loaded. This is possible by specifying the includes method of the Model.find call. With includes, Active Record ensures that all of the specified associations are loaded using the minimum possible number of queries.

Revisiting the above case, we could rewrite Client.limit(10) to use eager load addresses:

clients = Client.includes(:address).limit(10)

clients.each do |client|
  puts client.address.postcode
end

The above code will execute just 2 queries, as opposed to 11 queries in the previous case:

SELECT * FROM clients LIMIT 10
SELECT addresses.* FROM addresses
  WHERE (addresses.client_id IN (1,2,3,4,5,6,7,8,9,10))

13.1 Eager Loading Multiple Associations
Active Record lets you eager load any number of associations with a single Model.find call by using an array, hash, or a nested hash of array/hash with the includes method.

13.1.1 Array of Multiple Associations

Post.includes(:category, :comments)

This loads all the posts and the associated category and comments for each post.

13.1.2 嵌套关系

Category.includes(posts: [{ comments: :guest }, :tags]).find(1)

This will find the category with id 1 and eager load all of the associated posts, the associated posts' tags and comments, and every comment's guest association.

13.2 Specifying Conditions on Eager Loaded Associations
Even though Active Record lets you specify conditions on the eager loaded associations just like joins, the recommended way is to use joins instead.

However if you must do this, you may use where as you would normally.

Post.includes(:comments).where("comments.visible" => true)

This would generate a query which contains a LEFT OUTER JOIN whereas the joins method would generate one using the INNER JOIN function instead.

SELECT "posts"."id" AS t0_r0, ... "comments"."updated_at" AS t1_r5 FROM "posts" LEFT OUTER JOIN "comments" ON "comments"."post_id" = "posts"."id" WHERE (comments.visible = 1)

If there was no where condition, this would generate the normal set of two queries.

If, in the case of this includes query, there were no comments for any posts, all the posts would still be loaded. By using joins (an INNER JOIN), the join conditions must match, otherwise no records will be returned.

PS:上面是官方的使用说明,下面来一段我们自己代码的优化,贪婪加载的主要作用我感觉是减少数据库查询次数,其实查询时间上的优势不是特别的明显。
修改的代码是敏捷开发的数据库
使用嵌套加载减少了两次的数据库查询
Cart.includes(line_items: [:product]).find(31).line_items.each { |item| item.product.title }

一般我们的代码会如下:
Cart.find(31).line_items.each { |item| item.product.title }

时间对比图


天赢金创
338 声望21 粉丝

天赢金创,天赢金创,天赢金创,天赢金创,天赢金创,天赢金创天赢金创,天赢金创


引用和评论

0 条评论