From 9f126badc6e46220168a12b625d7a677cfe7ce25 Mon Sep 17 00:00:00 2001 From: phonghpham Date: Tue, 20 Feb 2024 16:53:18 -0600 Subject: [PATCH 1/2] Refactor HistoricalTrendService for performance optimization This commit addresses issue regarding performance of HistoricalDataCacheJob by optimizing HistoricalTrendService#series method while still maintaining existing functionality and data structure returned by HistoricalDataCacheJob#series. - preload `line_items` to avoid N+1 query - use ruby for aggregating line_item qty to reduce db queries - init month_offset and default_dates once outside of loop --- app/services/historical_trend_service.rb | 42 ++++++++++-------------- 1 file changed, 18 insertions(+), 24 deletions(-) diff --git a/app/services/historical_trend_service.rb b/app/services/historical_trend_service.rb index b44f912c9d..50a774706c 100644 --- a/app/services/historical_trend_service.rb +++ b/app/services/historical_trend_service.rb @@ -5,32 +5,26 @@ def initialize(organization_id, type) end def series - items = [] - - @organization.items.active.sort.each do |item| - next if item.line_items.where(itemizable_type: @type, item: item).blank? - - month_offset = [*1..12].rotate(Time.zone.today.month) - - dates = (1..12).index_with { |i| 0 } - - total_items(item.line_items, @type).each do |line_item| - month = line_item.dig(0).to_date.month - dates[(month_offset.index(month) + 1)] = line_item.dig(1) + # Preload line_items with a single query to avoid N+1 queries. + items_with_line_items = @organization.items.active + .includes(:line_items) + .where(line_items: {itemizable_type: @type, created_at: 1.year.ago.beginning_of_month..Time.current}) + .order(:name) + + month_offset = [*1..12].rotate(Time.zone.today.month) + default_dates = (1..12).index_with { |i| 0 } + + items = items_with_line_items.each_with_object([]) do |item, array_of_items| + dates = default_dates.deep_dup + + item.line_items.each do |line_item| + month = line_item.created_at.month + index = month_offset.index(month) + 1 + dates[index] = dates[index] + line_item.quantity end - items << {name: item.name, data: dates.values, visible: false} + array_of_items << { name: item.name, data: dates.values, visible: false } unless dates.values.sum.zero? end - - items.sort_by { |hsh| hsh[:name] } - end - - private - - def total_items(line_items, type) - line_items.where(created_at: 1.year.ago.beginning_of_month..Time.current) - .where(itemizable_type: type) - .group_by_month(:created_at) - .sum(:quantity) + items end end From f97732da7a001659c54222b1dc5c71e4fe277228 Mon Sep 17 00:00:00 2001 From: phonghpham Date: Thu, 22 Feb 2024 11:58:11 -0600 Subject: [PATCH 2/2] lint --- app/services/historical_trend_service.rb | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/app/services/historical_trend_service.rb b/app/services/historical_trend_service.rb index 50a774706c..f8615a625b 100644 --- a/app/services/historical_trend_service.rb +++ b/app/services/historical_trend_service.rb @@ -7,14 +7,14 @@ def initialize(organization_id, type) def series # Preload line_items with a single query to avoid N+1 queries. items_with_line_items = @organization.items.active - .includes(:line_items) - .where(line_items: {itemizable_type: @type, created_at: 1.year.ago.beginning_of_month..Time.current}) - .order(:name) + .includes(:line_items) + .where(line_items: {itemizable_type: @type, created_at: 1.year.ago.beginning_of_month..Time.current}) + .order(:name) month_offset = [*1..12].rotate(Time.zone.today.month) default_dates = (1..12).index_with { |i| 0 } - items = items_with_line_items.each_with_object([]) do |item, array_of_items| + items_with_line_items.each_with_object([]) do |item, array_of_items| dates = default_dates.deep_dup item.line_items.each do |line_item| @@ -23,8 +23,7 @@ def series dates[index] = dates[index] + line_item.quantity end - array_of_items << { name: item.name, data: dates.values, visible: false } unless dates.values.sum.zero? + array_of_items << {name: item.name, data: dates.values, visible: false} unless dates.values.sum.zero? end - items end end