Note that there are some explanatory texts on larger screens.

plurals
  1. POSQL slowness when doing ActiveRecord find on a HABTM relationship
    primarykey
    data
    text
    <p>I'm running Rails 2.3.5 with a MySQL database. I have a HABTM relationship between <code>Books</code> and <code>Users</code> and am trying to get all users who have a specified list of books (defined by an array of book names).</p> <p>I'm able to perform a <code>find</code> call that retrieves this list of users:</p> <pre><code>User.find( :all, :joins =&gt; :books, :conditions =&gt; { :books =&gt; { :name =&gt; book_names } } ) </code></pre> <p>However, this turns out to be extremely slow. After playing around in SQL, I found that the following call works much faster and retrieves the same results:</p> <pre><code>User.find_by_sql([ "SELECT users.* FROM users INNER JOIN books_users ON users.id = books_users.user_id WHERE books_users.book_id IN (SELECT id FROM books WHERE books.name IN (?))", book_names ]) </code></pre> <p>For the same query, the <code>find</code> call takes roughly 3000 ms on my computer whereas the <code>find_by_sql</code> call takes roughly 200 ms; this is an entire magnitude of speed difference. I suspect the culprit has something to do with the fact that the original <code>find</code> call is translated into a double <code>INNER JOIN</code> SQL query, equivalent to the following:</p> <pre><code>[ "SELECT users.* FROM users INNER JOIN books_users ON users.id = books_users.user_id INNER JOIN books ON books_users.book_id = books.id WHERE books.name IN (?)", book_names ] </code></pre> <p>My questions are:</p> <ul> <li>Does anyone know why this is the case? Why is the double <code>INNER JOIN</code> slower than my single <code>INNER JOIN</code> with a nested <code>SELECT</code> query?</li> <li>The <code>find_by_sql</code> call is not really taking advantage of the built-in support that Rails provides for HABTM relationships. In particular, it's surfacing the <code>books_users</code> join table that the Rails support typically abstracts away from the developer. Is there a way to specify the same query using a <code>find</code> call that hides this?</li> </ul>
    singulars
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload