2011-01-20 1 views
0

私はMySQLデータベースでRails 2.3.5を実行しています。 BooksUsersの間にHABTMの関係があり、特定の書籍リスト(書籍名の配列で定義)を持つすべてのユーザーを取得しようとしています。ActiveRecordを実行するとSQLの遅さがHABTM関係にある

私は、ユーザーのリストを取得しfindコールを実行することができるよ。しかし、これは非常に遅いことが判明

User.find(
    :all, 
    :joins  => :books, 
    :conditions => { :books => { :name => book_names } } 
) 

を。同じクエリのために

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 
]) 

find_by_sql呼び出しがおよそ200を取るのに対し、findコールが自分のコンピュータ上でおよそ3000ミリ秒かかります:SQLで遊んでた後、私は次の呼び出しは、はるかに高速に動作し、同じ結果を取得することがわかりましたミズ;これは速度差の大きさ全体です。私は犯人は元findコールは、次のと同等のダブルINNER JOIN SQLクエリに翻訳されているという事実とは何かを持っている疑いがある:

[ 
    "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 
] 

私の質問は以下のとおりです。

  • 誰もが知っていますなぜこれが当てはまるのですか?ダブルINNER JOINが入れ子になったSELECTクエリを持つ私の単一のINNER JOINよりも遅いのはなぜですか?
  • find_by_sql呼び出しは、RailsがHABTM関係に提供する組み込みサポートを実際に利用していません。特に、books_usersのジョイン・テーブルには、Railsがサポートしているものが一般的に開発者から抽象化されています。これを隠す呼び出しであるfindを使用して同じクエリを指定する方法はありますか?
+1

'books_users'テーブルの' book_id'フィールドと 'user_id'フィールドにインデックスを作成しましたか? –

+0

Ack ...私は何かを忘れていたことを知っていた。これだった!インデックスを追加した後、検索クエリは15ミリ秒かかるようになりました。 – Claw

+0

@dmarkow:回答として追加してください。私たちはあなたにポイントを与えることができます – nathanvda

答えて

1

あなたがbooks_usersであなたのbook_iduser_idフィールドにインデックスを必要とするように、それが鳴ります。

class AddIndices < ActiveRecord::Migration 
    def self.up 
    add_index :books_users, :book_id 
    add_index :books_users, :user_id 
    end 

    def self.down 
    remove_index :books_users, :book_id 
    remove_index :books_users, :user_id 
    end 
end 
0

を使用していますか:include対:join参加を良くしますか?上記のコメントの後

User.find(
    :all, 
    :include => :books, 
    :conditions => { :books => { :name => book_names } } 
) 
+0

残念ながら、それはまるで遅いようです。 – Claw

関連する問題