2

これが私のDBクエリです:

User has_many UserFollow (UserFollow は User モデル間の関係です)。ユーザー has_many の写真。Photo has_many PhotoFollow リレーションシップ (PhotoFollow は、User モデルと Photo モデルの間のリレーションシップです)。

@user_list = Array.new
user_followers = UserFollow.where("user_1_id = ?", current_user.id).includes(:follower)
user_followers.each do |f|
  @user_list << f.user
end

photos = Photo.where("user_id = ?", current_user.id).includes(:follow_relationships => [:photo])
photos.each do |p|
  p.follow_relationships.each do |f|
    @user_list << f.user if !@user_list.include? f.user
  end
end

if @user_list.size < 150
  users = User.where("verified = ? and first_name IS NOT NULL and last_name IS NOT NULL", true).includes(:solutions).limit(150 - @user_list.size)
  users.each do |u|
    @user_list << u if !@user_list.include? u
  end
end

これには明らかに途方もない時間がかかります。インクルードを使用すると役立ちますが、この一連の操作をより効率的に行う方法があるかどうか疑問に思っています。

ありがとう、リンゴ

4

6 に答える 6

2

最初に関連付けを追加します。

class User < ActiveRecord::Base
  has_many :follows_to_user, :class_name => 'UserFollow', :foreign_key => 'follower_id'
  has_many :follows_to_photo, :class_name => 'PhotoFollow', :foreign_key => 'user_id' # if you don't have it now
end

さて、最初の 2 つのクエリは、 AR::Relationスコープを返す1 つの SQL クエリ内でより洗練されたものにすることができます。

@user_list = User.includes(:follows_to_user => {}, :follows_to_photo => {:photo => {}}).where(["user_follows.user_1_id = :user_id OR photos.user_id = :user_id", :user_id => current_user.id])

約150... [更新]

もちろん、前の SQL ステートメントに条件とUNIONステートメント ( SQL 構文のみを使用) を追加するロジックを実装すると、AR::Relation が返され、少し速くなります。しかし、 Arrayを返しますが、怠惰なままにしてルビーのままにしておくことができます:

if (count = @user_list.count) && count < 150 # run COUNT just once and store value into local variable
  @user_list |= User.where("verified = ? and first_name IS NOT NULL and last_name IS NOT NULL", true).includes(:solutions).limit(150 - count)
end
于 2013-02-20T12:27:36.033 に答える
1

私の答えよりも良い方法が:user必要ですが、クエリを繰り返し処理するときにそれらをロードしているので、含めてみませんか?

@user_list = Array.new
user_followers = UserFollow.includes(:user).where("user_1_id = ?", current_user.id)
# why did you include followers?
user_followers.each do |f|
  @user_list << f.user
end

photos = Photo.includes(follow_relationships: { photo: :user }).where("user_id = ?", current_user.id)
photos.each do |p|
  p.follow_relationships.each do |f|
    @user_list << f.user unless @user_list.include? f.user
  end
end

if @user_list.size < 150
  users = User.where("verified = ? and first_name IS NOT NULL and last_name IS NOT NULL", true).limit(150 - @user_list.size)
  # why did you include solutions?
  users.each do |u|
    @user_list << u unless @user_list.include? u
  end
end

多分これはより速いです、私にはわかりません:

@follower_ids = UserFollow.where("user_1_id = ?", current_user.id).pluck(:user_1_id).uniq

@photo_ids = Photo.joins(follow_relationships: :photo)
@photo_ids = @photo_ids.where("user_id = ? and user_id not in (?)", current_user.id, @follower_ids)
@photo_ids = @photo_ids.pluck(:user_id).uniq

@followers = User.where("id in (?)", @follower_ids)
@photo_users = User.where("id in (?) and not in (?)", @photo_ids, @follower_ids) 

@array_size = (@follower_ids + @photo_ids).size
if @array_size < 150
  @users = User.where("verified = ? and first_name is not null and last_name is not null", true)
  @users = @users.where("id not in (?)", @photo_ids + @follower_ids).limit(150 - @array_size)
else
  @users = []
end

@final_array = @followers + @photo_users + @users

これが機能するかどうか、またはより高速かどうかはテストしていません。データベースクエリは多くなりますが、反復は少なくなります。

アップデート

ユーザー モデルに別の列を追加すると、フォロワー、写真、または何もないかどうかに応じて、1 から 3 の値で更新されます。

次に、行う必要があるのは次のとおりです。

# in User model
def self.valid_users
  where("verified = ? and first_name is not null and last_name is not null", true)
end


@users = User.valid_users.order("sortable ASC").limit(150)
于 2013-02-15T03:48:41.477 に答える
1

コードを見ると、ユーザーのリストを に取得することを計画しています@user_list。最初にユーザー ID のリストを作成して、不要な AR オブジェクトを作成しないようにすることができます

最初のコード

@user_list = Array.new
user_followers = UserFollow.where("user_1_id = ?", current_user.id).includes(:follower)
user_followers.each do |f|
  @user_list << f.user
end

に変更できます

# assuming you have a user_id column on user_follows table
user_ids = User.joins(:user_follows).where(user_follows: { user_1_id: current_user.id })
  .uniq.pluck('user_follows.user_id')

2 番目のコード

photos = Photo.where("user_id = ?", current_user.id).includes(:follow_relationships =>[:photo])
photos.each do |p|
  p.follow_relationships.each do |f|
    @user_list << f.user if !@user_list.include? f.user
  end
end

に変更できます

user_ids += Photo.where(user_id: current_user.id).joins(follow_relationships: :photo)
  .uniq.pluck('follow_relationships.user_id')

3 番目のコード

if @user_list.size < 150
  users = User.where("verified = ? and first_name IS NOT NULL and last_name IS NOT NULL", true).includes(:solutions).limit(150 - @user_list.size)
  users.each do |u|
    @user_list << u if !@user_list.include? u
  end
end

に変更できます

user_ids += users = User.where(verified: true)
  .where('first_name IS NOT NULL AND last_name IS NOT NULL')
  .where('id NOT IN (?)', user_ids)
  .limit(150 - user_ids.size).pluck(:id)

次に、次を使用してすべてのユーザーを取得できますuser_ids

@user_list = User.where(id: user_ids)
于 2013-02-20T01:48:27.897 に答える
0

テーブルのテーブル インデックスを設定しましたか?

まだ設定していない場合は、すべての外部キーと、条件に含める必要がある列に対して設定します。DB移行スクリプトで(もちろん、正しいテーブル名と列名を使用して)。特に大規模なデータセットがある場合は、クエリが高速化されます。

add_index :user_follows, :follower_id
add_index :user_follows, :followed_id

add_index :photos, :user_id

add_index :photo_follow_relationships, :photo_id
add_index :photo_follow_relationships, :follower_id

add_index :users, :verified
add_index :users, :first_name
add_index :users, :last_name

また、いくつかのコメントと推奨事項:

# ... [SNIP] Query and add to user list.
user_followers = []  # You are not actually using the UserFollow records. Unload
                     # them from memory. Otherwise, they will be stored until we
                     # leave the block.

# There is no need to fetch other Photo data here, and there is no need to load
# :photo for FollowRelationship. But there is a need to load :user.
photos = Photo.where(:user_id => current_user.id).select('photos.id').
    includes(:follow_relationships => [:user])
# ... [SNIP] Add to user list.
photos = []  # Unload photos.

# ... [SNIP] Your condition.
# There is no need to load :solutions for the users here.
users = User.where("verified = ? and first_name IS NOT NULL and last_name IS NOT NULL", true).limit(150 - @user_list.size)
# ... [SNIP] Add to user list.

もちろん、いくつかのマインドブランクの推奨事項のように、コードもリファクタリングするとより良いでしょう。has_many :throughアソシエーションを使用してコントローラーをクリーンアップすることもできます。

于 2013-02-15T09:32:38.200 に答える
0

次の関係をモデルに追加します

class User  
  has_many :user_follows
  has_many :inverse_user_follows, :class_name=>'UserFollow', :foreign_key=>:follower_id

  # followers for user
  has_many :followers, :through => :user_follows
  # users followed by user
  has_many :followed_users, :through => :inverse_user_follows, :source => :user


  # photos created by user
  has_many :photos

  has_many :photo_user_follows, :through => :photos, :source => :user_follows

  # followers for user's photo

  has_many :photo_followers, :through => :photo_user_follows, :source => :follower


  has_many :photo_follows
  # photos followed by user
  has_many :followed_photos, :source => :photo, :through => :photo_follows

end  

class UserFollow
  # index user_id and follower_id columns
  belongs_to :user
  belongs_to :follower, :class_name => "User"
end

写真関連モデル

class Photo
  # index user_id column
  belongs_to :user
  has_many   :photo_follows
  has_many   :followers, :through => :photo_follows
end

class PhotoFollow
  # index photo_id and follower_id columns
  belongs_to :photo
  belongs_to :follower, :class_name => "User"
end  

これで、現在のユーザーのフォロワー、現在のユーザーの写真のフォロワー、またはアクティブなユーザーであるユーザーを取得できます..

user_ids = current_user.follower_ids | current_user.photo_follower_ids

User.where("ids IN (?) OR 
   ( verified = ? and first_name IS NOT NULL and last_name IS NOT NULL )", 
  user_ids, true).limit(150)
于 2013-02-21T11:40:33.107 に答える
0

これは単なる推測です。

@user_list = current_user.followers.where("verified = ? and first_name IS NOT NULL and last_name IS NOT NULL", true).includes(:solutions, :photos => {:follow_relationships}).limit(150)

全体として、複雑さだけが原因で、すべてが間違っていると思います。何をしているのかはっきり読めない場合は、最初からやり直す必要があります。

于 2013-02-15T03:40:08.890 に答える