3

私の Rails プロジェクトには、Facebook の友達が既にサイトにいるかどうかをユーザーに示す機能があります。認証後、Facebook の友達を @fb_friends に読み込み、次のようにします。

  @fb_friends.each do |friend|
    friend_find = Authorization.find_by_uid_and_provider(friend[:identifier], 'facebook')
    if friend_find
      @fb_friends_on_cody << friend_find.user_id
      @fb_friends.delete(friend)
    end 
  end

基本的に、一致が見つかった場合 (Authorization テーブルを介して)、そのレコードを @fb_friends_on_cody にプッシュします。これは非常にコストのかかる操作であることがわかります。

  1. これは、フレンドごとに 1 回データベースにヒットします。したがって、私の場合、合計 582 のクエリが実行されました。

  2. 各 Authorization.find_by_uid_and_provider のパフォーマンスは低いです。次のようにインデックスを追加しました。

    add_index "authorizations", ["uid", "provider"], :name => "index_authorizations_on_uid_and_provider", :unique => true
    

最初のポイントに対処することで、多くのパフォーマンスの向上が見られると思います。おそらく、クエリ自体をより効率的にする方法がいくつかあります。これらの面でのヒントに感謝します。

解決

Unixmonkey のガイダンスを使用して、クエリの数を 582 から 1 に減らすことができました。最終的なコードは次のとおりです。

  friend_ids = @fb_friends.map{|f| f[:identifier] }
  authorizations = Authorization.where('provider = ? AND uid IN (?)','facebook',friend_ids)
  @fb_friends_on_cody = authorizations.map{ |a| { user_id: a.user_id, uid: a.uid }}
  @fb_friends.reject!{|f| @fb_friends_on_cody.map{|f| f[:uid]}.include?(f[:identifier]) } 
4

1 に答える 1

2

これでうまくいくと思います

friend_ids = @fb_friends.map(&:id)
authorizations = Authorization.where('provider = ? AND uid IN (?)','facebook',friend_ids)
@fb_friends_on_cody = authorizations.map(&:user_id)
@fb_friends.delete_all('id in (?)', @fb_friends_on_cody)
于 2012-07-26T20:42:06.143 に答える