A Journey On Rails

Performance problems with AssociationCollection

Posted in Rails by Vikram Venkatesan on December 21, 2009

While debugging down some performance problem recently, i narrowed down the problem to a piece of code that iterated a has_many association using each method. To check whether the block passed to ‘each’ is the culprit, I emptied the block; that din’t help much. Finally i changed the call to AssociationCollecton.to_a#each, and groovy!, it reduced the time taken by that whole block by more than 10 times. Since that piece of code was called thousands of time in the request i was trying to optimize, it was an optimiziation in order of seconds for that request. What more would i ask?!

I took that chance to learn the AssociationProxy and AssocationCollection code to find what exactly was causing the delay. I learn’t that AssociationCollection delegats all unknown calls to it to @target, the actual collection Array, through method_missing. So, each call was also going through the method_missing path, creating so much delay. Following is a piece of code explains the above behaviour.

t = Time.now

# Replace with your real object and association
some_object.some_has_many_assoc.each { #empty}
puts "#{(Time.now - t) * 1000000} microseconds"

To validate my understanding, i tried some_object.some_has_many_assoc.send(:load_target).each{} , so as to call the ‘each’ method directly on the collection; that ran many times faster than the previous version.

I knew method_missing can lead to performance problems, but din’t expect it to happen at such a magnitude!


Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: