Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gitlab-ce
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
1
Merge Requests
1
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
nexedi
gitlab-ce
Commits
a0a49f2f
Commit
a0a49f2f
authored
Jul 15, 2020
by
Dmitry Gruzd
Committed by
Terri Chu
Jul 22, 2020
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Fix N+1 /search issues
parent
0b1ff420
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
119 additions
and
43 deletions
+119
-43
app/controllers/search_controller.rb
app/controllers/search_controller.rb
+2
-1
app/models/issue.rb
app/models/issue.rb
+2
-0
changelogs/unreleased/fix-search-issues-n-plus-1.yml
changelogs/unreleased/fix-search-issues-n-plus-1.yml
+5
-0
ee/spec/requests/search_controller_spec.rb
ee/spec/requests/search_controller_spec.rb
+44
-42
spec/requests/search_controller_spec.rb
spec/requests/search_controller_spec.rb
+66
-0
No files found.
app/controllers/search_controller.rb
View file @
a0a49f2f
...
...
@@ -6,7 +6,8 @@ class SearchController < ApplicationController
include
RendersCommits
SCOPE_PRELOAD_METHOD
=
{
projects: :with_web_entity_associations
projects: :with_web_entity_associations
,
issues: :with_web_entity_associations
}.
freeze
around_action
:allow_gitaly_ref_name_caching
...
...
app/models/issue.rb
View file @
a0a49f2f
...
...
@@ -87,6 +87,8 @@ class Issue < ApplicationRecord
scope
:order_created_at_desc
,
->
{
reorder
(
created_at: :desc
)
}
scope
:preload_associated_models
,
->
{
preload
(
:assignees
,
:labels
,
project: :namespace
)
}
scope
:with_web_entity_associations
,
->
{
preload
(
:author
,
:project
)
}
scope
:with_api_entity_associations
,
->
{
preload
(
:timelogs
,
:assignees
,
:author
,
:notes
,
:labels
,
project:
[
:route
,
{
namespace: :route
}]
)
}
scope
:with_label_attributes
,
->
(
label_attributes
)
{
joins
(
:labels
).
where
(
labels:
label_attributes
)
}
scope
:with_alert_management_alerts
,
->
{
joins
(
:alert_management_alert
)
}
scope
:with_prometheus_alert_events
,
->
{
joins
(
:issues_prometheus_alert_events
)
}
...
...
changelogs/unreleased/fix-search-issues-n-plus-1.yml
0 → 100644
View file @
a0a49f2f
---
title
:
Avoid N+1 of issue associations in Search
merge_request
:
36941
author
:
type
:
performance
ee/spec/requests/search_controller_spec.rb
View file @
a0a49f2f
...
...
@@ -15,58 +15,60 @@ RSpec.describe SearchController, type: :request do
get
search_path
,
params:
params
end
shared_examples
'an efficient database result'
do
it
'avoids N+1 database queries'
do
create
(
object
,
*
creation_traits
,
creation_args
)
ensure_elasticsearch_index!
control
=
ActiveRecord
::
QueryRecorder
.
new
(
skip_cached:
false
)
{
send_search_request
(
params
)
}
create_list
(
object
,
3
,
*
creation_traits
,
creation_args
)
ensure_elasticsearch_index!
expect
{
send_search_request
(
params
)
}.
not_to
exceed_all_query_limit
(
control
).
with_threshold
(
threshold
)
end
end
describe
'GET /search'
do
context
'when elasticsearch is enabled'
,
:elastic
,
:sidekiq_inline
do
before
do
stub_ee_application_setting
(
elasticsearch_search:
true
,
elasticsearch_indexing:
true
)
end
let
(
:creation_traits
)
{
[]
}
context
'for issues scope'
do
let
(
:object
)
{
:issue
}
let
(
:creation_args
)
{
{
project:
project
}
}
let
(
:params
)
{
{
search:
'*'
,
scope:
'issues'
}
}
let
(
:threshold
)
{
0
}
it_behaves_like
'an efficient database result'
end
context
'for merge_request scope'
do
before
do
create
(
:merge_request
,
target_branch:
'feature_1'
,
source_project:
project
)
create
(
:merge_request
,
target_branch:
'feature_2'
,
source_project:
project
)
create
(
:merge_request
,
target_branch:
'feature_3'
,
source_project:
project
)
create
(
:merge_request
,
target_branch:
'feature_4'
,
source_project:
project
)
ensure_elasticsearch_index!
end
it
'avoids N+1 queries'
do
control
=
ActiveRecord
::
QueryRecorder
.
new
(
skip_cached:
false
)
{
send_search_request
(
scope:
'merge_requests'
,
search:
'*'
)
}
create
(
:merge_request
,
target_branch:
'feature_5'
,
source_project:
project
)
create
(
:merge_request
,
target_branch:
'feature_6'
,
source_project:
project
)
create
(
:merge_request
,
target_branch:
'feature_7'
,
source_project:
project
)
create
(
:merge_request
,
target_branch:
'feature_8'
,
source_project:
project
)
ensure_elasticsearch_index!
# some N+1 queries still exist
expect
{
send_search_request
(
scope:
'merge_requests'
,
search:
'*'
)
}
.
not_to
exceed_all_query_limit
(
control
)
end
let
(
:creation_traits
)
{
[
:unique_branches
]
}
let
(
:object
)
{
:merge_request
}
let
(
:creation_args
)
{
{
source_project:
project
}
}
let
(
:params
)
{
{
search:
'*'
,
scope:
'merge_requests'
}
}
let
(
:threshold
)
{
0
}
it_behaves_like
'an efficient database result'
end
context
'for project scope'
do
before
do
create
(
:project
,
:public
)
ensure_elasticsearch_index!
end
it
'avoids N+1 queries'
do
control
=
ActiveRecord
::
QueryRecorder
.
new
(
skip_cached:
false
)
{
send_search_request
(
scope:
'project'
,
search:
'*'
)
}
create_list
(
:project
,
3
,
:public
)
ensure_elasticsearch_index!
# some N+1 queries still exist
# each project requires 3 extra queries
# - one count for forks
# - one count for open MRs
# - one count for open Issues
expect
{
send_search_request
(
scope:
'project'
,
search:
'*'
)
}
.
not_to
exceed_all_query_limit
(
control
).
with_threshold
(
9
)
end
let
(
:creation_traits
)
{
[
:public
]
}
let
(
:object
)
{
:project
}
let
(
:creation_args
)
{
{}
}
let
(
:params
)
{
{
search:
'*'
,
scope:
'projects'
}
}
# some N+1 queries still exist
# each project requires 3 extra queries
# - one count for forks
# - one count for open MRs
# - one count for open Issues
let
(
:threshold
)
{
9
}
it_behaves_like
'an efficient database result'
end
end
end
...
...
spec/requests/search_controller_spec.rb
0 → 100644
View file @
a0a49f2f
# frozen_string_literal: true
require
'spec_helper'
RSpec
.
describe
SearchController
,
type: :request
do
let_it_be
(
:user
)
{
create
(
:user
)
}
let_it_be
(
:group
)
{
create
(
:group
)
}
let_it_be
(
:project
)
{
create
(
:project
,
:public
,
:repository
,
:wiki_repo
,
name:
'awesome project'
,
group:
group
)
}
before_all
do
login_as
(
user
)
end
def
send_search_request
(
params
)
get
search_path
,
params:
params
end
shared_examples
'an efficient database result'
do
it
'avoids N+1 database queries'
do
create
(
object
,
*
creation_traits
,
creation_args
)
control
=
ActiveRecord
::
QueryRecorder
.
new
(
skip_cached:
false
)
{
send_search_request
(
params
)
}
create_list
(
object
,
3
,
*
creation_traits
,
creation_args
)
expect
{
send_search_request
(
params
)
}.
not_to
exceed_all_query_limit
(
control
).
with_threshold
(
threshold
)
end
end
describe
'GET /search'
do
let
(
:creation_traits
)
{
[]
}
context
'for issues scope'
do
let
(
:object
)
{
:issue
}
let
(
:creation_args
)
{
{
project:
project
}
}
let
(
:params
)
{
{
search:
'*'
,
scope:
'issues'
}
}
let
(
:threshold
)
{
0
}
it_behaves_like
'an efficient database result'
end
context
'for merge_request scope'
do
let
(
:creation_traits
)
{
[
:unique_branches
]
}
let
(
:object
)
{
:merge_request
}
let
(
:creation_args
)
{
{
source_project:
project
}
}
let
(
:params
)
{
{
search:
'*'
,
scope:
'merge_requests'
}
}
let
(
:threshold
)
{
0
}
it_behaves_like
'an efficient database result'
end
context
'for project scope'
do
let
(
:creation_traits
)
{
[
:public
]
}
let
(
:object
)
{
:project
}
let
(
:creation_args
)
{
{}
}
let
(
:params
)
{
{
search:
'*'
,
scope:
'projects'
}
}
# some N+1 queries still exist
# each project requires 3 extra queries
# - one count for forks
# - one count for open MRs
# - one count for open Issues
let
(
:threshold
)
{
9
}
it_behaves_like
'an efficient database result'
end
end
end
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment