Hello there,
it’s late in Bremen, so I will keep this thing as short as possible: I just wasted the complete day’s work at Tansporter due to a bad preparation… dumb me! (Remember: Benchmark before any optimization!)
I tried to optimize some of our ActiveRecord find statements, installed a whole new column on a table solely for that reason, changed the model to fill this new column right and then changed the actual method I would like to spice up.
It was a 70 line monster of very ugly code. After refactoring it, there were just 40 lines left and it was very cool, clean and beautiful code. The main change: I replaced a find statement which returned a very huuuuge result set, which I had to iterate and do some computing on every element, with 4 very cool queries with just one result, each.
Sounds cool, but unfortunately it isn’t.
After I had a short “wow, that’s great stuff!” experience, I thought it might not be unclever to benchmark the new method and compare it to the old one.
And here comes the trouble: The old method finished in about 0.018 seconds, the new one needed somewhat between 0.54 and 0.4 seconds… What a pitty!
So I switched back to the ugly version, to my rescue the added column could be used elsewhere so my effort was not completely useless.
What I’ve learned: One query with a large result set apparently performs MUCH better than 4 (not absolute trivial) queries with a very small result set, even if you have to iterate through the whole big result set.
Anyway I stumbled upon two cool, small things today that are worth mentioning them:
1st: Get a random “thing” out of the database.
Until today we managed this with a method at the particular model looking somehow like this:
1 2 3 4 5 6 7 8 9 10 | def self.random_good good = nil while (!good) begin good = Good.find(rand(Good.maximum(:id))) rescue ActiveRecord::RecordNotFound => e end end good end |
Today I received my copy of The Rails Way and one of the first things I found was the native, MySQL “ORDER BY RAND()” function. Pretty cool. Because database portability doesn’t really matter for us, the same function as above now looks like this:
1 2 3 | def self.random_good Good.find(:first, :order => 'RAND()') end |
2nd: Don’t forget about the power of ActiveRecord’s :include option!
The :include option of a find statement is very powerful! I read about this maybe a year ago, never needed it again and forgot about it. Today I rediscovered the veeeeery nice nesting capability:
1 2 | tickets = Ticket.find(:all, :include => [:user, {:operator => {:open_tickets => :user}}]) |
I can’t really believe it, but after this find statement you can do this:
1 | tickets.first.operator.open_tickets.last.user.nickname |
…without ANY extra query! It’s all joined together in the one find query and still runs at a reasonable pace.
Ok, now it’s really time for me to go to bed.
Stay tuned,
Thorben
FEtMab-Team









