2012-06-27 38 views
0

我有以下的ActiveRecord查詢。當我的測試環境中的消息數量爲50時運行正常,但是當我們將其投入生產並且消息數量增加到5000時,響應時間接近30秒。不好。不好調整Rails ActiveRecord查詢

如何更有效地執行此查詢,以便隨着消息數量的增長保持快速。如果查詢尚未完成,查詢將查找所有消息中的所有警報。

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 
+0

是你對你的表使用的是什麼類型的索引? – robbrit

+0

良好的捕獲 - 在引用該消息的警報表上沒有索引。將添加它並更新你的表現。 – bluedevil2k

+0

注意,使用'[]'創建一個空數組比使用'Array.new'更傳統。你也可以使用'+ ='將數組添加到數組中而不是'@array = @array + ...'。 – tadman

回答

3

大廈關閉傑西的回答,稍微好一點的是創建一個範圍,只選擇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 } 
+0

ohhhh很好。我喜歡包括範圍的想法;沒有任何發現! –

+0

如果你多次使用一組特定的條件,爲它們定義一個「範圍」幾乎總是一個好主意。 – tadman

+0

在這種特殊情況下,你並不需要拉姆達。你可以這麼說:scope:pending_alerts,joins(:alerts).where(「alerts.completed = false」) – Salil

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 
+1

而不是在提取的警報上做「選擇」,爲什麼不通過排除它們的條件呢? – tadman

+0

嘗試你的第二塊,我得到這個錯誤 - 顯示應用程序/視圖/警報/ index.json.rabl其中線#1提出:

can't convert Array into Hash
bluedevil2k

+0

@tadman我喜歡chrismohr的pending_alerts範圍的建議 –