Commit dbd59feb authored by Dmitry Gruzd's avatar Dmitry Gruzd

Merge branch...

Merge branch '326754-api-endpoint-groups-id-search-blobs-scope-executes-more-than-100-sql-queries' into 'master'

Reduce queries on group search API for blobs scope [RUN ALL RSPEC] [RUN AS-IF-FOSS]

See merge request gitlab-org/gitlab!58495
parents 41303181 41e95956
---
title: Reduce queries on group search API for blobs scope
merge_request: 58495
author:
type: performance
...@@ -11,6 +11,11 @@ module EE ...@@ -11,6 +11,11 @@ module EE
ELASTICSEARCH_SCOPES = %w(wiki_blobs blobs commits notes).freeze ELASTICSEARCH_SCOPES = %w(wiki_blobs blobs commits notes).freeze
override :scope_preload_method
def scope_preload_method
super.merge(blobs: :with_api_commit_entity_associations).freeze
end
override :verify_search_scope! override :verify_search_scope!
def verify_search_scope!(resource:) def verify_search_scope!(resource:)
if ELASTICSEARCH_SCOPES.include?(params[:scope]) && !use_elasticsearch?(resource) if ELASTICSEARCH_SCOPES.include?(params[:scope]) && !use_elasticsearch?(resource)
......
...@@ -134,27 +134,52 @@ RSpec.describe API::Search, factory_default: :keep do ...@@ -134,27 +134,52 @@ RSpec.describe API::Search, factory_default: :keep do
it 'avoids N+1 queries' do it 'avoids N+1 queries' do
control = ActiveRecord::QueryRecorder.new { get api(endpoint, user), params: { scope: 'commits', search: 'folder' } } control = ActiveRecord::QueryRecorder.new { get api(endpoint, user), params: { scope: 'commits', search: 'folder' } }
project_2 = create(:project, :public, :repository, :wiki_repo, name: 'awesome project 2') project_2 = create(:project, :public, :repository, :wiki_repo, group: group, name: 'awesome project 2')
project_3 = create(:project, :public, :repository, :wiki_repo, name: 'awesome project 3')
project_2.repository.index_commits_and_blobs project_2.repository.index_commits_and_blobs
project_3.repository.index_commits_and_blobs 3.times do |i|
commit_sha = project.repository.create_file(user, "#{i}", "folder #{i}", message: "committing folder #{i}", branch_name: 'master')
project.repository.commit(commit_sha)
end
project.repository.index_commits_and_blobs
ensure_elasticsearch_index! ensure_elasticsearch_index!
# Some N+1 queries still exist # N+1 queries still exist (ci_pipelines)
expect { get api(endpoint, user), params: { scope: 'commits', search: 'folder' } }.not_to exceed_query_limit(control).with_threshold(9) expect { get api(endpoint, user), params: { scope: 'commits', search: 'folder' } }.not_to exceed_query_limit(control).with_threshold(5)
# support global, group, and project search results expected counts
expected_count = level == :project ? 5 : 7
expect(json_response.count).to be expected_count
end end
end end
context 'for blobs scope' do context 'for blobs scope' do
it_behaves_like 'response is correct', schema: 'public_api/v4/blobs' do it_behaves_like 'response is correct', schema: 'public_api/v4/blobs' do
before do before do
get api(endpoint, user), params: { scope: 'blobs', search: 'monitors' } get api(endpoint, user), params: { scope: 'blobs', search: 'folder' }
end end
end end
it_behaves_like 'pagination', scope: 'blobs' it_behaves_like 'pagination', scope: 'blobs'
it 'avoids N+1 queries' do
control = ActiveRecord::QueryRecorder.new { get api(endpoint, user), params: { scope: 'blobs', search: 'Issue team' } }
project_2 = create(:project, :public, :repository, :wiki_repo, group: group, name: 'awesome project 2')
project_2.repository.index_commits_and_blobs
3.times do |i|
commit_sha = project.repository.create_file(user, "#{i}", "Issue team #{i}", message: "#{i}", branch_name: 'master')
project.repository.commit(commit_sha)
end
project.repository.index_commits_and_blobs
ensure_elasticsearch_index!
expect { get api(endpoint, user), params: { scope: 'blobs', search: 'Issue team' } }.not_to exceed_query_limit(control)
# support global, group, and project search results expected counts
expected_count = level == :project ? 6 : 9
expect(json_response.count).to be expected_count
end
context 'filters' do context 'filters' do
def results_filenames def results_filenames
json_response.map { |h| h['filename'] }.compact json_response.map { |h| h['filename'] }.compact
......
...@@ -22,13 +22,15 @@ module API ...@@ -22,13 +22,15 @@ module API
users: Entities::UserBasic users: Entities::UserBasic
}.freeze }.freeze
SCOPE_PRELOAD_METHOD = { def scope_preload_method
merge_requests: :with_api_entity_associations, {
projects: :with_api_entity_associations, merge_requests: :with_api_entity_associations,
issues: :with_api_entity_associations, projects: :with_api_entity_associations,
milestones: :with_api_entity_associations, issues: :with_api_entity_associations,
commits: :with_api_commit_entity_associations milestones: :with_api_entity_associations,
}.freeze commits: :with_api_commit_entity_associations
}.freeze
end
def search(additional_params = {}) def search(additional_params = {})
search_params = { search_params = {
...@@ -60,7 +62,7 @@ module API ...@@ -60,7 +62,7 @@ module API
end end
def preload_method def preload_method
SCOPE_PRELOAD_METHOD[params[:scope].to_sym] scope_preload_method[params[:scope].to_sym]
end end
def verify_search_scope!(resource:) def verify_search_scope!(resource:)
......
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