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

我已经对这种方法进行了基准测试,有问题的代码是系列循环,它生成一系列日期,然后映射出一个新数组,每个日期都有一个数量。这样,无论是否有金额,我都会得到一个包含每个日期金额的系列。

当查询只返回几个日期时,它运行得相当快。但是将开始日期设置在一两年后,它变得非常缓慢。真正的罪犯是.detect方法。扫描活动记录对象数组非常慢。

有没有更快的方法来生成这个系列?

4

2 回答 2

1

orders_by_day 按“pg_print_date_group”分组,因此它应该是对象的“日期”哈希。所以你为什么不做

(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

由于您的代码中的主要罪犯是必须一次又一次扫描数组的检测方法,我建议您颠倒创建系列的顺序,以便您只扫描一次数组,并且您的代码在 O (n) 时间。

尝试以下方式:

系列 = []
next_date = start_time.to_date
orders_by_day.each 做 |order|
  而 order.print_date.to_date < next_date
    系列 << 0.0
    next_date = next_date.next
  结尾
  系列 << order.total_amount.to_f.round(2)
  下一个日期 += 1
结尾
而 next_date < Date.today
    系列 << 0.0
    next_date = next_date.next
结尾

请注意,我的代码未经测试;)

于 2011-05-04T19:18:34.937 回答