Living on the edge (of Rails) #5 - better eager loading and more

Another week of edge Rails changes, featured on the Rails Envy podcast. This weeks’ report covers changes from 21 Jan 2008 to 27 Jan 2008 (the day the Rails Envy podcast was recorded).

Eager loading :includes does pre-loading

The current gem Rails behavior when loading associations with something like

Author.find(:all, :include => [:posts, :comments])

is to make a big query with multiple joins that fetches all the associations in the same query (for you RDBMS geeks, the “cartesian product”).

Frederick Cheung (fcheung on the Rails Trac) has contributed an impressive optimization to this by pre-loading the associations rather than trying to eager loading with one big query. So a find like this:

Author.find(:all, :include => [:posts, :comments])

would first load all the authors, then all the posts, and then all the comments in 3 smaller, faster queries.

The main benefit of this (depending on your data): Running X simple queries (to fetch authors, then posts and comments) rather than one mega-query that joins all the associated tables is faster most of the time. The result set is often smaller as well.

More details can be found at ticket #9640 on the Rails Trac.

Related changeset: http://dev.rubyonrails.org/changeset/8672

composed_of aggregations can now be used in finder conditions

You can now use value objects that you’ve previously specified that your model is composed_of in the finder conditions hash. E.g. if you have a Customer that has a balance aggregation:

class Customer < ActiveRecord::Base
  composed_of :balance, :class_name => "Money", :mapping => %w(balance amount)
end

You can now pass a Money value object to Customer#find:

Customer.find(:all, :conditions => { :balance => Money.new(20, "USD") })

Convenient.

Related changeset: http://dev.rubyonrails.org/changeset/8671

New helper: label_tag

A label_tag helper has been missing for quite awhile since the label helper was added. No longer:

label_tag 'name'
# => <label for="name">Name</label>

label_tag 'name', 'Your name'
# => <label for="name">Your name</label>

Related changeset: http://dev.rubyonrails.org/changeset/8685

New ActiveSupport class: ActiveSupport::TimeWithZone

A new ActiveSupport::TimeWithZone class has been introduced to make timezone support in Rails easier. Ryan Daigle has a good writeup on this.

A word of warning though: this is still work in progress, as Geoff Buesing, the core team member responsible for these timezone changes, has more to add on how his plans for the timezone puzzle in the comments.

Related changeset: http://dev.rubyonrails.org/changeset/8696

map.root can be easily aliased

map.root now accept a single symbol as an argument to declare an alias. Just a little something to keep your routes a little more DRY, e.g.:

map.new_session :controller => 'sessions', :action => 'new'
map.root :new_session

Related changeset: http://dev.rubyonrails.org/changeset/8738

As usual, let me know of any inaccuracies or any suggestions you may have in the comments!

8 Comments & TrackBacks (Add yours)

The paper doll icon that precedes each comment is an idea conceived by Vanessa Tan.

Paper doll icon
Dr Nic's Gravatar

In case you need any encouraging to continue with these posts: “Please continue with these posts”.

Or more succinctly:

+1

Posted by: Dr Nic on January 30, 2008 8pm

Paper doll icon
otavio's Gravatar

Hy chu, great post. First i tought that “:includes does pre-loading” will be awesome. Then i’ve started to fell a little bit worried about performance for big tables. Then i saw the benchmarks at the ticket and it looks great again :). But it’s not quite finished yet, is it?

Posted by: otavio on January 30, 2008 10pm

Paper doll icon
A Fresh Cup » Blog Archive » Double Shot #134's Gravatar

[…] The joy of independence: trying to nail down an elusive contract. There might be room in my dance card coming up in the future if you’re interested in talking. […]

Posted by: A Fresh Cup » Blog Archive » Double Shot #134 on January 30, 2008 10pm

Paper doll icon
Ropiku's Gravatar

Vote it on Ruby Reddit.

Posted by: Ropiku on January 30, 2008 10pm

Paper doll icon
Daniel Fischer's Gravatar

Great stuff Chu! As Dr. Nic said “+1″!!!!

Posted by: Daniel Fischer on January 31, 2008 3am

Paper doll icon
Mark Wilden's Gravatar

A Cartesian join matches every record from one table with every record from another table. Suffice it to say that Rails doesn’t do this. :)

///ark

Posted by: Mark Wilden on January 31, 2008 6am

Paper doll icon
Chu Yeow's Gravatar

@Dr Nic, Daniel Fischer: Thanks for the encouragement!

@otavio: Yes you’re right - it’s not finished yet (there are still some bugs to fix), but I thought I’d get the word out since the decision to switch to pre-loading has been made :).

@Mark Wilden: You’re right - I’m the one who needs to brush up on my set theory. I think what I really mean to say is that the strategy now is to avoid making monster joins involving multiple tables.

Posted by: Chu Yeow on January 31, 2008 10am

Paper doll icon
How to Avoid Hanging Yourself with Rails's Gravatar

[…] Presentation - How to Avoid Hanging Yourself with Rails Faker - faker.rubyforge.org ‘mrj’s ActiveRecord select/include patch - http://dev.rubyonrails.org/attachment/ticket/7147/init.5.rb include preloading optimisation - http://blog.codefront.net/2008/01/30/living-on-the-edge-of-rails-5-better-eager-loading-and-more/ […]

Posted by: How to Avoid Hanging Yourself with Rails on February 13, 2008 10am

You can subscribe to the RSS feed for comments on this post.

Post a comment

(required)

(required, but never displayed)


You can format your comments using XHTML. Your email address will not be displayed or used for nefarious purposes.

Only following tags are allowed:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>