From d369acb516eed108d6897f93be549f0a2f302c9c Mon Sep 17 00:00:00 2001
From: Jarka Kadlecova <jarka@gitlab.com>
Date: Tue, 7 Feb 2017 14:15:07 +0100
Subject: [PATCH] Improve issues filtering performance

---
 app/finders/issuable_finder.rb                | 35 +++++++++++--------
 app/finders/issues_finder.rb                  |  4 +++
 app/finders/merge_requests_finder.rb          |  6 ++++
 .../25503_issues_finder_performance.yml       |  4 +++
 4 files changed, 35 insertions(+), 14 deletions(-)
 create mode 100644 changelogs/unreleased/25503_issues_finder_performance.yml

diff --git a/app/finders/issuable_finder.rb b/app/finders/issuable_finder.rb
index f49301e2631..2fca012252e 100644
--- a/app/finders/issuable_finder.rb
+++ b/app/finders/issuable_finder.rb
@@ -33,15 +33,17 @@ class IssuableFinder
     items = by_scope(items)
     items = by_state(items)
     items = by_group(items)
-    items = by_project(items)
     items = by_search(items)
-    items = by_milestone(items)
     items = by_assignee(items)
     items = by_author(items)
-    items = by_label(items)
     items = by_due_date(items)
     items = by_non_archived(items)
     items = by_iids(items)
+    items = by_milestone(items)
+    items = by_label(items)
+
+    # Filtering by project HAS TO be the last because we use the project IDs yielded by the issuable query thus far
+    items = by_project(items)
     sort(items)
   end
 
@@ -107,8 +109,7 @@ class IssuableFinder
     @project = project
   end
 
-  def projects
-    return @projects if defined?(@projects)
+  def projects(items = nil)
     return @projects = project if project?
 
     projects =
@@ -117,7 +118,7 @@ class IssuableFinder
       elsif group
         GroupProjectsFinder.new(group).execute(current_user)
       else
-        ProjectsFinder.new.execute(current_user)
+        projects_finder.execute(current_user, item_project_ids(items))
       end
 
     @projects = projects.with_feature_available_for_user(klass, current_user).reorder(nil)
@@ -257,9 +258,9 @@ class IssuableFinder
   def by_project(items)
     items =
       if project?
-        items.of_projects(projects).references_project
-      elsif projects
-        items.merge(projects.reorder(nil)).join_project
+        items.of_projects(projects(items)).references_project
+      elsif projects(items)
+        items.merge(projects(items).reorder(nil)).join_project
       else
         items.none
       end
@@ -314,13 +315,14 @@ class IssuableFinder
       if filter_by_no_milestone?
         items = items.left_joins_milestones.where(milestone_id: [-1, nil])
       elsif filter_by_upcoming_milestone?
-        upcoming_ids = Milestone.upcoming_ids_by_projects(projects)
+        upcoming_ids = Milestone.upcoming_ids_by_projects(projects(items))
         items = items.left_joins_milestones.where(milestone_id: upcoming_ids)
       else
         items = items.with_milestone(params[:milestone_title])
+        items_projects = projects(items)
 
-        if projects
-          items = items.where(milestones: { project_id: projects })
+        if items_projects
+          items = items.where(milestones: { project_id: items_projects })
         end
       end
     end
@@ -334,9 +336,10 @@ class IssuableFinder
         items = items.without_label
       else
         items = items.with_label(label_names, params[:sort])
+        items_projects = projects(items)
 
-        if projects
-          label_ids = LabelsFinder.new(current_user, project_ids: projects).execute(skip_authorization: true).select(:id)
+        if items_projects
+          label_ids = LabelsFinder.new(current_user, project_ids: items_projects).execute(skip_authorization: true).select(:id)
           items = items.where(labels: { id: label_ids })
         end
       end
@@ -396,4 +399,8 @@ class IssuableFinder
   def current_user_related?
     params[:scope] == 'created-by-me' || params[:scope] == 'authored' || params[:scope] == 'assigned-to-me'
   end
+
+  def projects_finder
+    @projects_finder ||= ProjectsFinder.new
+  end
 end
diff --git a/app/finders/issues_finder.rb b/app/finders/issues_finder.rb
index f542f72a386..08713272947 100644
--- a/app/finders/issues_finder.rb
+++ b/app/finders/issues_finder.rb
@@ -41,4 +41,8 @@ class IssuesFinder < IssuableFinder
       user_id: user.id,
       project_ids: user.authorized_projects(Gitlab::Access::REPORTER).select(:id))
   end
+
+  def item_project_ids(items)
+    items&.reorder(nil)&.select(:project_id)
+  end
 end
diff --git a/app/finders/merge_requests_finder.rb b/app/finders/merge_requests_finder.rb
index b76ca389f38..1eec45d9cb5 100644
--- a/app/finders/merge_requests_finder.rb
+++ b/app/finders/merge_requests_finder.rb
@@ -20,4 +20,10 @@ class MergeRequestsFinder < IssuableFinder
   def klass
     MergeRequest
   end
+
+  private
+
+  def item_project_ids(items)
+    items&.reorder(nil)&.select(:target_project_id)
+  end
 end
diff --git a/changelogs/unreleased/25503_issues_finder_performance.yml b/changelogs/unreleased/25503_issues_finder_performance.yml
new file mode 100644
index 00000000000..87964269c6d
--- /dev/null
+++ b/changelogs/unreleased/25503_issues_finder_performance.yml
@@ -0,0 +1,4 @@
+---
+title: Filter by projects in the end of search
+merge_request: 9030
+author:
-- 
GitLab