Probably you already know about n+1 queries problem, read this post if you want to learn how to detect those kind of queries.
For example:
class User < ActiveRecord::Base has_many :items end class Item < ActiveRecord::Base belongs_to :user end
If we have 2 users, and several items we have controller like this:
def index @users = User.find(:all) end
and in the view we have something like this:
<% @users.each do |user| %>
<%= user.items.collect(&:name) %>
<% end %>
If we watch the queries on the log, we should see something like this :
SELECT * FROM "users"
SELECT * FROM "items" WHERE ("items".user_id = 1)
SELECT * FROM "items" WHERE ("items".user_id = 2)
if we have 1000 items, that means we are doing 1000+1 queries!
Off course we can fix it like this (eager loading):
def index @users = User.find(:all, :include => :items) end
And now we only have two queries.
Detecting it in our application is another matter. If we have huge project, detecting it can be hard work and time wasting. I found a cool plugin/gem that help detecting n+1 queries problem, called Bullet. You can install it as a gem:
sudo gem install flyerhzm-bullet --source http://gems.github.com
or as a plugin
script/plugin install git://github.com/flyerhzm/bullet.git
or you can build the gem right from the source from:
git clone git://github.com/flyerhzm/bullet.git cd bullet gem build bullet.gemspec sudo gem install bullet --local
If you are using it as a gem, don’t forget to include this in your environment.rb:
config.gem 'flyerhzm-bullet', :lib => 'bullet', :source => 'http://gems.github.com'
include this in development.rb, and remember not to use bullet on production:
config.after_initialize do Bullet.enable = true Bullet::Association.alert = true Bullet::Association.bullet_logger = true Bullet::Association.rails_logger = false end
You want to make two profiles in your Firefox, one for regular browsing, and one without caching enabled since sometimes it is not working in regular profile. So disable caching on your browser if you want to see pop-up box if we are doing n+1 queries. Also Bullet detect eager loading that is not used. I attached a screenshot so you can see it in action:
