# Find eager loads correct records but generates excess queries (Rails 2.1)

**URL:** <https://www.ruby-forum.com/t/find-eager-loads-correct-records-but-generates-excess-queries-rails-2-1/166580>\
**Category:** Rails\
**Created:** [April 27, 2009, 4:19pm UTC](https://www.ruby-forum.com/t/find-eager-loads-correct-records-but-generates-excess-queries-rails-2-1/166580 "2009-04-27T16:19:12Z")\
**Posts on this page:** 3\
**Page:** 1

<div class="post-metadata">

**Author:** ![davidy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/7ea924/32.png) [@davidy](https://www.ruby-forum.com/u/davidy)\
**Post date:** [April 27, 2009, 4:19pm UTC](https://www.ruby-forum.com/t/find-eager-loads-correct-records-but-generates-excess-queries-rails-2-1/166580/1 "2009-04-27T16:19:12Z")

</div>

Models:  
S :has\_many F; F :belongs\_to P; S :has\_many P :through F.

Query looks like this:  
S.find\_all\_by\_key([array of keys], :include =\> [:F, :P])

This produces the correct and expected result, but very slowly. On the  
log:  
SELECT \* FROM S WHERE KEY IN (keys)  
SELECT \* FROM F WHERE S\_ID IN (S.ids from first query)  
SELECT \* FROM F WHERE S\_ID IN (S.ids from first query) [same query  
twice]  
SELECT \* FROM P WHERE ID IN (ids from second query)

At this point all the required data has been retrieved and Rails is  
looking good. Time to quit. However:  
SELECT \* FROM P WHERE ID = first id from second query  
SELECT \* FROM P WHERE ID = second id from second query  
… [typically about 50-200 queries, one query per P.ID]

Q1. Why so many extraneous queries?  
Q2. Is there an easy fix, or is this just too hard for Rails?  
Q3. In general, is it possible to control eager loading at a per-query  
level?

---

<div class="post-metadata">

**Author:** ![davidy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/7ea924/32.png) [@davidy](https://www.ruby-forum.com/u/davidy)\
**Post date:** [April 27, 2009, 4:25pm UTC](https://www.ruby-forum.com/t/find-eager-loads-correct-records-but-generates-excess-queries-rails-2-1/166580/2 "2009-04-27T16:25:04Z")

</div>

On Apr 27, 3:18 pm, davidy [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> SELECT \* FROM F WHERE S\_ID IN (S.ids from first query) [same query  
> twice]  
> SELECT \* FROM P WHERE ID IN (ids from second query)
> 
> At this point all the required data has been retrieved and Rails is  
> looking good. Time to quit. However:  
> SELECT \* FROM P WHERE ID = first id from second query  
> SELECT \* FROM P WHERE ID = second id from second query  
> … [typically about 50-200 queries, one query per P.ID]

That’s odd. is that from your eager loading or from your subsequent  
use of the data ( also anonymising the table names to S, F, P makes it  
rather hard to read than if there were meaningful names) (in  
particular eager loading is unidirectional - if person has\_many posts,  
then Person.find(:all, :include =\> :posts) doesn’t eager load  
post.person

Fred

---

<div class="post-metadata">

**Author:** ![davidy](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/d/7ea924/32.png) [@davidy](https://www.ruby-forum.com/u/davidy)\
**Post date:** [April 28, 2009, 2:49am UTC](https://www.ruby-forum.com/t/find-eager-loads-correct-records-but-generates-excess-queries-rails-2-1/166580/3 "2009-04-28T02:49:48Z")

</div>

All SQL queries are generated by that one, single find() call. This is  
really scary – there is nothing in the documentation to suggest that  
it can do this kind of “fake join”, or the performance impact it can  
have.

Sorry about the anonymisation, but the real table names would only  
confuse things worse.

I suspect this is a bug/feature of Rails eager loading, caused by the  
“triangular” relationships. S loads F using has\_many, then F loads P  
using belongs\_to, then S loads P again using has\_many through. It  
“should” be smart enough not to, but that logic isn’t in there. The  
documentation is absolutely no help, and the source code is way too  
complicated for this bear.

Q3 is the answer. I fixed the problem (with dramatic performance  
improvement) using :include {hash}, like so.  
S.find\_all\_by\_key([array of keys], :include =\> {:F =\> :P})

Magic!
