1

次のクエリはかなり高速に実行されますが、後で実行する必要のある一連の処理により、このメソッドの速度が大幅に低下します。私はリファクタリングにいくつかの助けを使うことができました。

def self.sum_amount_chart_series(start_time)
  orders_by_day = Widget.archived.not_void.
                  where(:print_datetime => start_time.beginning_of_day..Time.zone.now.end_of_day).
                  group(pg_print_date_group).
                  select("#{pg_print_date_group} as print_date, sum(amount) as total_amount")


  # THIS IS WHAT IS SLOWING THE METHOD DOWN!
  (start_time.to_date..Date.today).map do |date|
    order = orders_by_day.detect { |order| order.print_date.to_date == date }
    order && order.total_amount.to_f.round(2) || 0.0
  end

end

def self.pg_print_date_group
  "CAST((print_datetime + interval '#{tz_offset_hours} hours') AS date)"
end

私はこのメソッドのベンチマークを行いました。問題のあるコードは、一連の日付を生成し、各日付の量を含む新しい配列をマップする一連のループです。このようにして、金額の有無に関係なく、すべての日付の金額を含むシリーズを取得します。

クエリが数個の日付のみを返す場合、かなり高速に実行されます。ただし、開始日を1〜2年前に戻すと、非常に遅くなります。本当の犯罪者は.detectメソッドです。activerecordオブジェクトの配列をスキャンするのは非常に遅いです。

このシリーズを生成するためのより高速な方法はありますか?

4

2 に答える 2

1

orders_by_dayは「pg_print_date_group」でグループ化されているため、オブジェクトに対する「date」のハッシュである必要があります。だからあなたはただやってみませんか

(start_time.to_date..Date.today).map do |date|
  order = orders_by_day[date.to_s(:db)]
  order && order.total_amount.to_f.round(2) || 0.0
end

それはあなたの実行のビッグOを真剣に減らすはずです。そして、私が誤解していて、orders_by_dayがハッシュではない場合は、それをハッシュに前処理してからマップを実行します。すべての日付を検出する必要はありません。

于 2011-05-04T19:16:53.100 に答える
0

コードの主な違反者は、配列を何度もスキャンする必要がある検出メソッドであるため、配列を1回だけスキャンし、コードがOで実行されるように、シリーズを作成する順序を逆にすることをお勧めします。 (n)時間。

次の線に沿って何かを試してください:

シリーズ=[]
next_date = start_time.to_date
orders_by_day.each do | order |
  order.print_date.to_date <next_date
    シリーズ<<0.0
    next_date = next_date.next
  終わり
  シリーズ<<order.total_amount.to_f.round(2)
  next_date + = 1
終わり
next_date <Date.today
    シリーズ<<0.0
    next_date = next_date.next
終わり

私のコードはテストされていないことに注意してください;)

于 2011-05-04T19:18:34.937 に答える