summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStan Hu <stanhu@gmail.com>2018-05-31 00:14:24 -0700
committerStan Hu <stanhu@gmail.com>2018-05-31 00:18:05 -0700
commitef253a1ee7c03edf9773574a843b5c458e9add36 (patch)
tree57e4d1d49aa0107351a19b74d92542327a9a8065
parent37a7b590c6b7a881ed014f99571a1f44cb45acab (diff)
downloadgitlab-ce-ef253a1ee7c03edf9773574a843b5c458e9add36.tar.gz
Eliminate cached N+1 queries for projects in Issue API
In CE, every `Issue` entity is also a `ProjectEntity`, which calls `entity&.project.try(:id)` to show the project ID. In an API request with 100 issues, this would hit the Rails statement cache 100 times for the same project and cause unnecessary overhead as related models would also be loaded. In EE, we call `Issue#supports_weight?` for each issue, which then calls `project&.feature_available?(:issue_weights)`. If the project is not preloaded, this incurs additional overhead, as each individual Project object has to be queried. This can lead to a significant performance hit. In loading the CE project with 100 issues, this contributed to at least 22% of the load time. See https://gitlab.com/gitlab-org/gitlab-ce/issues/47031 for why testing this is a bit tricky.
-rw-r--r--changelogs/unreleased/sh-fix-issue-api-perf-n-plus-one.yml5
-rw-r--r--lib/api/issues.rb2
2 files changed, 6 insertions, 1 deletions
diff --git a/changelogs/unreleased/sh-fix-issue-api-perf-n-plus-one.yml b/changelogs/unreleased/sh-fix-issue-api-perf-n-plus-one.yml
new file mode 100644
index 00000000000..57ba081326f
--- /dev/null
+++ b/changelogs/unreleased/sh-fix-issue-api-perf-n-plus-one.yml
@@ -0,0 +1,5 @@
+---
+title: Eliminate cached N+1 queries for projects in Issue API
+merge_request:
+author:
+type: performance
diff --git a/lib/api/issues.rb b/lib/api/issues.rb
index 6d75e8817c4..b64f465ce56 100644
--- a/lib/api/issues.rb
+++ b/lib/api/issues.rb
@@ -16,7 +16,7 @@ module API
args[:scope] = args[:scope].underscore if args[:scope]
issues = IssuesFinder.new(current_user, args).execute
- .preload(:assignees, :labels, :notes, :timelogs)
+ .preload(:assignees, :labels, :notes, :timelogs, :project)
issues.reorder(args[:order_by] => args[:sort])
end