0

次のActiveRecordクエリがあります。テスト環境でメッセージ数が50の場合は正常に動作しましたが、本番環境に移行してメッセージ数が5000に増えると、応答時間は30秒に近づきました。良くない。

どうすればこのクエリをより効率的に実行できるので、メッセージの数が増えても迅速に処理できます。クエリは、メッセージがまだ完了していない場合、すべてのメッセージからすべてのアラートを検索します。

class AlertsController < ApplicationController
  before_filter :get_user
  respond_to :json, :html

 def index
    @messages = current_user.messages.where(:active => true).order("created_at ASC")

    @alerts = Array.new
    @messages.each do |message|
        if (message.alerts.count > 0)
          @alerts = @alerts + message.alerts.where(:completed => false)
        end
    end

    respond_to do |format|
      format.html
      format.json
    end
  end

end


class Alert < ActiveRecord::Base
    belongs_to :message

class Message < ActiveRecord::Base
  has_many :alerts, dependent: :destroy
4

2 に答える 2

3

Jesseの答えから構築すると、 のみを選択するスコープを作成するのが少し良いでしょうpending_alerts。このようにして、渡すデータが少なくなり、データベースがより多くの作業を行うようになります。

class Message < ActiveRecord::Base
  scope :pending_alerts, lambda {
    alerts.where(:completed => false)
  }
}

次に、コントローラーで:

@messages = current_user.messages.includes(:pending_alerts).where(:active => true).order("created_at ASC")  
@alerts = @messages.map { |m| m.alerts } 
于 2012-06-27T14:20:49.200 に答える
1

これは n+1 問題のようです。ドキュメントはこちら ( Solution to N + 1 queries problem を検索)

@messages = current_user.messages.includes(:alerts).where(:active => true).order("created_at ASC")

次に、@alerts をよりシンプルにします:

@alerts = @messages.map do |message|
  message.alerts.select {|alert| !alert.completed}
end
于 2012-06-27T14:08:15.400 に答える