summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSean McGivern <sean@gitlab.com>2016-11-25 13:57:56 +0000
committerSean McGivern <sean@gitlab.com>2016-12-01 12:24:55 +0000
commit8ee072808651b21535ba4444e3a9e2361c860c49 (patch)
treeea5ad529a08afe7531a417fb2fa2ac9d91c00258
parent79b5bfc113973e8564f7d78f5e76347693245900 (diff)
downloadgitlab-ce-8ee072808651b21535ba4444e3a9e2361c860c49.tar.gz
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.
-rw-r--r--app/finders/issuable_finder.rb26
-rw-r--r--app/helpers/issuables_helper.rb9
2 files changed, 29 insertions, 6 deletions
diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index 9a74e36870b..001c83ccb4b 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -49,6 +49,32 @@ class IssuableFinder
execute.find_by(*params)
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
return @group if defined?(@group)
diff --git a/app/helpers/issuables_helper.rb b/app/helpers/issuables_helper.rb
index 6584aa3edd5..b85e3f9e60e 100644
--- a/app/helpers/issuables_helper.rb
+++ b/app/helpers/issuables_helper.rb
@@ -180,12 +180,9 @@ module IssuablesHelper
end
def issuables_count_for_state(issuable_type, state)
- issuables_finder = public_send("#{issuable_type}_finder")
-
- params = issuables_finder.params.merge(state: state)
- finder = issuables_finder.class.new(issuables_finder.current_user, params)
-
- finder.execute.page(1).total_count
+ @counts ||= {}
+ @counts[issuable_type] ||= public_send("#{issuable_type}_finder").count_by_state
+ @counts[issuable_type][state]
end
IRRELEVANT_PARAMS_FOR_CACHE_KEY = %i[utf8 sort page]