Ruby on rails 查询和加速-图表的日期序列

Ruby on rails 查询和加速-图表的日期序列,ruby-on-rails,activerecord,series,Ruby On Rails,Activerecord,Series,下面的查询运行得相当快,但随后需要进行的系列处理确实减慢了此方法的速度。我需要一些重构方面的帮助 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).

下面的查询运行得相当快,但随后需要进行的系列处理确实减慢了此方法的速度。我需要一些重构方面的帮助

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
我已经对这个方法进行了基准测试,有问题的代码是series循环,它在其中生成一系列日期,然后映射出一个新数组,其中包含每个日期的数量。通过这种方式,我可以得到一个序列,其中包含每个日期的金额,不管它是否有金额

当查询只返回几个日期时,它运行得相当快。但是,如果将开始日期推迟一两年,那么它的速度将变得极其缓慢。真正的罪犯是侦查方法。扫描activerecord对象数组的速度非常慢


是否有更快的方法生成此系列?

订单按日期按“打印日期组”分组,因此它应该是对象的“日期”散列。那你为什么不这么做呢

(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

这将大大降低你跑步的难度。如果我误解了,你的订单不是散列,那么先将其预处理成散列,然后运行映射,你肯定不想检测每个日期

orders\u by\u day按“pg\u print\u date\u 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(n)时间内运行

尝试以下几点:

series = [] next_date = start_time.to_date orders_by_day.each do |order| while order.print_date.to_date < next_date series << 0.0 next_date = next_date.next end series << order.total_amount.to_f.round(2) next_date += 1 end while next_date < Date.today series << 0.0 next_date = next_date.next end 系列=[] 下一个日期=开始时间到日期 逐日订购。每个人都要订购| 而order.print_date.to_date序列由于代码中的主犯是必须反复扫描数组的检测方法,因此我建议您颠倒创建序列的顺序,以便只扫描数组一次,并且代码以O(n)时间运行

尝试以下几点:

series = [] next_date = start_time.to_date orders_by_day.each do |order| while order.print_date.to_date < next_date series << 0.0 next_date = next_date.next end series << order.total_amount.to_f.round(2) next_date += 1 end while next_date < Date.today series << 0.0 next_date = next_date.next end 系列=[] 下一个日期=开始时间到日期 逐日订购。每个人都要订购| 而order.print_date.to_date您是否尝试过在日期循环中执行SQL查询(只需按提供的日期获取订单,如果为零,则返回0.0)?让MySQL为您进行所有查找可能会更快,而不是让Ruby进行查找。-一些答案可以指示您更改查询,以包括所有日期,并避免使用检测。@Vijay:我确实试过了。由于我使用Postgres,我尝试将右连接与generate_series合并,但始终无法使其正常工作(它遗漏了0.0数量的日期)。您是否尝试过在日期循环中执行SQL查询(只需按提供的日期获取订单,如果为零,则返回0.0)?让MySQL为您进行所有查找可能会更快,而不是让Ruby进行查找。-一些答案可以指示您更改查询,以包括所有日期,并避免使用检测。@Vijay:我确实试过了。由于我使用Postgres,我尝试将一个右连接与generate_series合并,但始终无法使其正常工作(它遗漏了0.0 amount的日期)。你让我orders_by_day.index_by(&:print_date)’,它使用print_date从AR数组中创建散列,然后我可以使用生成的散列访问金额。快点!你带我去…'orders_by_day.index_by(&:print_date)’,它使用print_date从AR数组中创建散列,然后我可以使用生成的散列访问金额。快点!