diff options
author | Stan Hu <stanhu@gmail.com> | 2019-03-02 09:31:36 -0800 |
---|---|---|
committer | Stan Hu <stanhu@gmail.com> | 2019-03-06 07:03:46 -0800 |
commit | 062efe4f7a83fb2b6d951b314692cca9ee8731cd (patch) | |
tree | 2907359acdf497130b38c75555056226189af829 /app | |
parent | a592a78072bb44fed1a25c25f2cabdc4cf4bc0bd (diff) | |
download | gitlab-ce-062efe4f7a83fb2b6d951b314692cca9ee8731cd.tar.gz |
Significantly reduce N+1 queries in /api/v4/todos endpoint
By preloading associations and batching issuable metadata lookups,
we can significantly cut the number of SQL queries needed to load
the Todos API endpoint.
On GitLab.com, my own tests showed my user's SQL queries went
from 365 to under 60 SQL queries.
Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/40378
Diffstat (limited to 'app')
-rw-r--r-- | app/models/issue.rb | 1 | ||||
-rw-r--r-- | app/models/merge_request.rb | 7 | ||||
-rw-r--r-- | app/models/todo.rb | 9 |
3 files changed, 16 insertions, 1 deletions
diff --git a/app/models/issue.rb b/app/models/issue.rb index 071ad50fddc..deab53d25e7 100644 --- a/app/models/issue.rb +++ b/app/models/issue.rb @@ -64,6 +64,7 @@ class Issue < ActiveRecord::Base scope :order_closest_future_date, -> { reorder('CASE WHEN issues.due_date >= CURRENT_DATE THEN 0 ELSE 1 END ASC, ABS(CURRENT_DATE - issues.due_date) ASC') } scope :preload_associations, -> { preload(:labels, project: :namespace) } + scope :with_api_entity_associations, -> { preload(:timelogs, :assignees, :author, :notes, :labels, project: [:route, { namespace: :route }] ) } scope :public_only, -> { where(confidential: false) } scope :confidential_only, -> { where(confidential: true) } diff --git a/app/models/merge_request.rb b/app/models/merge_request.rb index b67797f5404..acf80addc6a 100644 --- a/app/models/merge_request.rb +++ b/app/models/merge_request.rb @@ -184,6 +184,13 @@ class MergeRequest < ActiveRecord::Base scope :assigned, -> { where("assignee_id IS NOT NULL") } scope :unassigned, -> { where("assignee_id IS NULL") } scope :assigned_to, ->(u) { where(assignee_id: u.id)} + scope :with_api_entity_associations, -> { + preload(:author, :assignee, :notes, :labels, :milestone, :timelogs, + latest_merge_request_diff: [:merge_request_diff_commits], + metrics: [:latest_closed_by, :merged_by], + target_project: [:route, { namespace: :route }], + source_project: [:route, { namespace: :route }]) + } participant :assignee diff --git a/app/models/todo.rb b/app/models/todo.rb index d9b86d941b6..2b0dee875a3 100644 --- a/app/models/todo.rb +++ b/app/models/todo.rb @@ -31,7 +31,13 @@ class Todo < ActiveRecord::Base belongs_to :note belongs_to :project belongs_to :group - belongs_to :target, polymorphic: true, touch: true # rubocop:disable Cop/PolymorphicAssociations + belongs_to :target, -> { + if self.klass.respond_to?(:with_api_entity_associations) + self.with_api_entity_associations + else + self + end + }, polymorphic: true, touch: true # rubocop:disable Cop/PolymorphicAssociations belongs_to :user delegate :name, :email, to: :author, prefix: true, allow_nil: true @@ -52,6 +58,7 @@ class Todo < ActiveRecord::Base scope :for_type, -> (type) { where(target_type: type) } scope :for_target, -> (id) { where(target_id: id) } scope :for_commit, -> (id) { where(commit_id: id) } + scope :with_api_entity_associations, -> { preload(:target, :author, :note, group: :route, project: [:route, { namespace: :route }]) } state_machine :state, initial: :pending do event :done do |