diff --git a/app/controllers/dashboard/projects_controller.rb b/app/controllers/dashboard/projects_controller.rb index 71f18694613..1dc89943f7f 100644 --- a/app/controllers/dashboard/projects_controller.rb +++ b/app/controllers/dashboard/projects_controller.rb @@ -70,6 +70,7 @@ class Dashboard::ProjectsController < Dashboard::ApplicationController .new(params: finder_params, current_user: current_user) .execute .includes(:route, :creator, :group, namespace: [:route, :owner]) + .preload(:project_feature) .page(finder_params[:page]) prepare_projects_for_rendering(projects) diff --git a/changelogs/unreleased/sh-project-feature-nplus-one.yml b/changelogs/unreleased/sh-project-feature-nplus-one.yml new file mode 100644 index 00000000000..425ae7815c1 --- /dev/null +++ b/changelogs/unreleased/sh-project-feature-nplus-one.yml @@ -0,0 +1,5 @@ +--- +title: Remove N+1 SQL query loading project feature in dashboard +merge_request: 32169 +author: +type: performance diff --git a/spec/features/dashboard/projects_spec.rb b/spec/features/dashboard/projects_spec.rb index e2100c8562b..f362172e712 100644 --- a/spec/features/dashboard/projects_spec.rb +++ b/spec/features/dashboard/projects_spec.rb @@ -220,4 +220,26 @@ describe 'Dashboard Projects' do expect(find('input#merge_request_target_branch', visible: false).value).to eq 'master' end end + + it 'avoids an N+1 query in dashboard index' do + create(:ci_pipeline, :with_job, status: :success, project: project, ref: project.default_branch, sha: project.commit.sha) + visit dashboard_projects_path + + control_count = ActiveRecord::QueryRecorder.new { visit dashboard_projects_path }.count + + new_project = create(:project, :repository, name: 'new project') + create(:ci_pipeline, :with_job, status: :success, project: new_project, ref: new_project.commit.sha) + new_project.add_developer(user) + + ActiveRecord::QueryRecorder.new { visit dashboard_projects_path }.count + + # There are three known N+1 queries: + # 1. Project#open_issues_count + # 2. Project#open_merge_requests_count + # 3. Project#forks_count + # + # In addition, ProjectsHelper#load_pipeline_status also adds an + # additional query. + expect { visit dashboard_projects_path }.not_to exceed_query_limit(control_count + 4) + end end