Dahlia Bock

25Jan/120

ActiveRecord: Avoid N + 1 queries

Ruby 1.8.7, Rails 2.3.8

I made a rookie mistake a few days ago but thanks to a colleague of mine who smacked me on the hand, I had a chance to correct it. Consider the following model:

class Order < ActiveRecord::Base
  belongs_to :account
end
class Account < ActiveRecord::Base
  has_many :orders
end

If you are retrieving a group of accounts and accessing each of its orders, you would be encountering an N + 1 query problem. Meaning you would be firing 1 query to retrieve 1 account, and if that account has N orders, N + 1 queries would be executed.

accounts = Account.find(:all, :limit => 10)
 
accounts.each do |a|
  puts a.orders
end

ActiveRecord uses default_scope to avoid the N + 1 situation.

class Account < ActiveRecord::Base
  default_scope :include => :order
  has_many :orders
end

This will execute just 2 queries:

SELECT "accounts".* FROM "accounts" LIMIT 10
SELECT "orders".* FROM "orders" WHERE "orders"."account_id" IN (1, 2, 3, 4, 5, 6, 7, 8, 9, 10)

The :include option can be used in a named scope as well. Long running queries are bad (of course), especially when you are dealing with tens of thousands of records.

Lesson well learnt (and remembered). Thanks Blake.

Comments (0) Trackbacks (0)

No comments yet.


Leave a comment

(required)

No trackbacks yet.