This project is archived and is in readonly mode.
allow explicit association preloading (:load vs :include)
Reported by cainlevy | July 8th, 2008 @ 07:49 PM | in 2.x
The attached patch adds a :load option for ActiveRecord.
I've found it useful to be able to specify associations for preloading through a :load option that is independent of the :include option. There are two benefits that I can see:
1) When any :include association is referenced in condition/grouping/order SQL, then all :include associations are retrieved via SQL joins. Adding a separate :load option allows a developer to optimize which associations are joined and which are preloaded.
2) Associations that are preloaded do not affect the result set, whereas associations that are loaded through SQL joins do.
In my case, I'm using the :load option to set up named_scope's that do nothing more than optimize a result set for a particular context, e.g. Posts.for_home_page.by_recency.
Comments and changes to this ticket
-
cainlevy July 9th, 2008 @ 12:09 AM
After some discussion in #rails-contrib, I came to see this new option as completing a triad:
- :include names associations that should be eager loaded but may also be needed for sql references (e.g. in conditions, orders, etc.)
- :joins names associations that are needed for sql references but should not be loaded
- :load names associations that should be loaded but are not needed for sql references
API bloat is something to be taken seriously. In this case I feel like the new option rounds out the use cases, and is not bloat.
Thoughts?
-
hiroshi August 17th, 2008 @ 01:36 PM
I express approval about the :load option.
cainlevy suggested capabilities against optimization, moreover, I point out that a problem of 'join' eager loading has_many association with group option.
For example, Ticket has_many :tags, and I would like to find tickets which has tags, 'foo' and 'bar', also I prefer eager loading because search result will show tags for each ticket. The code can be like that:
# Ticket.find(:all, :include => :tags, :joins => "INNER JOIN tags AS t ON t.ticket_id = tickets.id", :conditions => ["t.name IN (:tags)", {:tags => ['foo', 'bar']}], :group => "t.ticket_id HAVING COUNT(t.ticket_id) >= 2")
This call of find() internally uses find_with_associations (join eager loading) instead of preload_associations. Any of the resulted ticket included only one tag (because ticket is grouped by own id), but they may have two or more tags.
-
hiroshi August 17th, 2008 @ 01:49 PM
I also found a quick option (a hack?) for explicit association preloading.
tickets = Ticket.find(:all, # :include => :tags, :joins => "INNER JOIN tags AS t ON t.ticket_id = tickets.id", :conditions => ["t.name IN (:tags)", {:tags => ['foo', 'bar']}], :group => "t.ticket_id HAVING COUNT(t.ticket_id) >= 2") Ticket.send(:preload_associations, tickets, :tags)
It worked (for me).
-
Pratik August 18th, 2008 @ 04:30 PM
Please discuss in the core mailing list. Meanwhile, you could write a simple plugin with hiroshi's suggestion.
-
Pratik August 18th, 2008 @ 04:31 PM
- State changed from new to wontfix
-
cainlevy August 18th, 2008 @ 10:38 PM
I use the following patch in my own project:
class ActiveRecord::Base class << self private def find_every_with_explicit_preloading(options) returning find_every_without_explicit_preloading(options) do |records| to_load = merge_includes(scope(:find, :load), options[:load]) preload_associations(records, to_load) if to_load end end alias_method_chain :find_every, :explicit_preloading VALID_FIND_OPTIONS << :load end end
Create your profile
Help contribute to this project by taking a few moments to create your personal profile. Create your profile »
<h2 style="font-size: 14px">Tickets have moved to Github</h2>
The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>