Commit 8ee07280 authored by Sean McGivern's avatar Sean McGivern

Count all issuable states at once

Instead of doing n queries for n states, do one query to get all the
counts grouped by state, and figure out what the count is for each state
is from that. We can still cache the individual counts (it can't hurt),
but this will help with initial load.

Note that the `opened` scope on `Issuable` includes the `opened` and
`reopened` states, which is why there's a special case.
parent 79b5bfc1
...@@ -49,6 +49,32 @@ class IssuableFinder ...@@ -49,6 +49,32 @@ class IssuableFinder
execute.find_by(*params) execute.find_by(*params)
end end
# We often get counts for each state by running a query per state, and
# counting those results. This is typically slower than running one query
# (even if that query is slower than any of the individual state queries) and
# grouping and counting within that query.
#
def count_by_state
count_params = params.merge(state: nil, sort: nil)
labels_count = label_names.any? ? label_names.count : 1
finder = self.class.new(current_user, count_params)
counts = Hash.new(0)
# Searching by label includes a GROUP BY in the query, but ours will be last
# because it is added last. Searching by multiple labels also includes a row
# per issuable, so we have to count those in Ruby - which is bad, but still
# better than performing multiple queries.
#
finder.execute.reorder(nil).group(:state).count.each do |key, value|
counts[Array(key).last.to_sym] += value / labels_count
end
counts[:all] = counts.values.sum
counts[:opened] += counts[:reopened]
counts
end
def group def group
return @group if defined?(@group) return @group if defined?(@group)
......
...@@ -180,12 +180,9 @@ module IssuablesHelper ...@@ -180,12 +180,9 @@ module IssuablesHelper
end end
def issuables_count_for_state(issuable_type, state) def issuables_count_for_state(issuable_type, state)
issuables_finder = public_send("#{issuable_type}_finder") @counts ||= {}
@counts[issuable_type] ||= public_send("#{issuable_type}_finder").count_by_state
params = issuables_finder.params.merge(state: state) @counts[issuable_type][state]
finder = issuables_finder.class.new(issuables_finder.current_user, params)
finder.execute.page(1).total_count
end end
IRRELEVANT_PARAMS_FOR_CACHE_KEY = %i[utf8 sort page] IRRELEVANT_PARAMS_FOR_CACHE_KEY = %i[utf8 sort page]
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment