扩展性差Rails ActiveRecord查询

时间:2012-06-27 14:01:17

标签: ruby-on-rails ruby ruby-on-rails-3

我有以下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

2 个答案:

答案 0 :(得分:3)

建立Jesse的答案,更好一点就是创建一个范围来只选择pending_alerts,这样你就可以传递更少的数据,并让数据库完成更多的工作。 / p>

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 } 

答案 1 :(得分: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