Why does Active Record trigger an extra query when used. Includes a method for retrieving data.

I have the following model structure:

class Group < ActiveRecord::Base
  has_many    :group_products, :dependent => :destroy
  has_many    :products, :through => :group_products

class Product < ActiveRecord::Base
  has_many  :group_products, :dependent => :destroy
  has_many  :groups, :through => :group_products

class GroupProduct < ActiveRecord::Base
  belongs_to :group
  belongs_to :product


I wanted to keep my database queries to a minimum, so I decided to use include.In the console I tried something like

groups = Group.includes(:products)


my development logs show the following calls,

Group Load (403.0ms)  SELECT `groups`.* FROM `groups`
GroupProduct Load (60.0ms)  SELECT `group_products`.* FROM `group_products` WHERE (`group_products`.group_id IN (1,3,14,15,16,18,19,20,21,22,23,24,25,26,27,28,29,30,33,42,49,51))
Product Load (22.0ms)  SELECT `products`.* FROM `products` WHERE (`products`.`id` IN (382,304,353,12,63,103,104,105,262,377,263,264,265,283,284,285,286,287,302,306,307,308,328,335,336,337,340,355,59,60,61,247,309,311,66,30,274,294,324,350,140,176,177,178,64,240,327,332,338,380,383,252,254,255,256,257,325,326))
Product Load (10.0ms)  SELECT `products`.* FROM `products` WHERE (`products`.`id` = 377) LIMIT 1


I could analyze the initial three calls that were needed but didn't get the reason the last database call was made,

 Product Load (10.0ms)  SELECT `products`.* FROM `products` WHERE (`products`.`id` = 377) LIMIT 1


Any idea why this is happening? Thank you in advance.:)


source to share

3 answers

I don't think the fourth request is coming from this line of code (or the collection it created). Even if you did something like groups.products.find(product_id)

sometime later, you will see a much more complex query with inner joins in the join table. It looks like there should be a separate Product.find(product_id)

or something similar in your code .



I had a similar problem when releasing a call where()

. The problem was caused by some "lazy evaluation" being done for ActiveRecords::Relation

(like the sailor mentioned above). The solution is to just add a .to_a

at the end of the call. It should work for your expression includes()

above as well. For more information see:




Now you can easily find an N + 1 request request with the bullet gem (help kill N + 1 requests and unused download.)

Use this gem, it will tell you where you need to work to kill the N + 1 call and also indicate if the download requires.

It helps me to use this and then try it, you get a solution to your problem.

Read the below article explaining to you more about the different ways of doing eager loading -

3 ways to load (preload) in Rails 3 and 4



All Articles