Commit f9e21787 authored by Stan Hu's avatar Stan Hu

Eliminate N+1 queries in /api/groups/:id

In https://gitlab.com/gitlab-org/gitlab-ce/merge_requests/15475/diffs, a
significant amount of work went into eliminating N+1 queries in the
/api/groups/:id/projects endpoint. We can reuse the
`Entities::Project.prepare_relation` call on the projects.

In a group with 2,573 projects on GitLab.com, this change significantly
improves performance:

* 18019 SQL queries down to 21
* Time spent in DB: 70 s down to 384 ms

Closes https://gitlab.com/gitlab-org/gitlab-ce/issues/49845
parent d4d4ebad
---
title: Eliminate N+1 queries in /api/groups/:id
merge_request: 24513
author:
type: performance
...@@ -344,19 +344,23 @@ module API ...@@ -344,19 +344,23 @@ module API
class GroupDetail < Group class GroupDetail < Group
expose :projects, using: Entities::Project do |group, options| expose :projects, using: Entities::Project do |group, options|
GroupProjectsFinder.new( projects = GroupProjectsFinder.new(
group: group, group: group,
current_user: options[:current_user], current_user: options[:current_user],
options: { only_owned: true } options: { only_owned: true }
).execute ).execute
Entities::Project.prepare_relation(projects)
end end
expose :shared_projects, using: Entities::Project do |group, options| expose :shared_projects, using: Entities::Project do |group, options|
GroupProjectsFinder.new( projects = GroupProjectsFinder.new(
group: group, group: group,
current_user: options[:current_user], current_user: options[:current_user],
options: { only_shared: true } options: { only_shared: true }
).execute ).execute
Entities::Project.prepare_relation(projects)
end end
end end
......
...@@ -382,6 +382,20 @@ describe API::Groups do ...@@ -382,6 +382,20 @@ describe API::Groups do
expect(response_project_ids(json_response, 'shared_projects')) expect(response_project_ids(json_response, 'shared_projects'))
.to contain_exactly(projects[:public].id, projects[:internal].id) .to contain_exactly(projects[:public].id, projects[:internal].id)
end end
it 'avoids N+1 queries' do
get api("/groups/#{group1.id}", admin)
control_count = ActiveRecord::QueryRecorder.new do
get api("/groups/#{group1.id}", admin)
end.count
create(:project, namespace: group1)
expect do
get api("/groups/#{group1.id}", admin)
end.not_to exceed_query_limit(control_count)
end
end end
context "when authenticated as admin" do context "when authenticated as admin" do
......
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