Commit b7b72a44 authored by Douwe Maan's avatar Douwe Maan
Browse files

Drastically improve project search performance by no longer searching namespace name

parent 94d6ca2fd784
......@@ -18,6 +18,7 @@
include SelectForProjectAuthorization
include Routable
include GroupDescendant
include Gitlab::SQL::Pattern
extend Gitlab::ConfigHelper
extend Gitlab::CurrentSettings
......@@ -424,7 +425,5 @@
#
# query - The search query as a String.
def search(query)
ptable = arel_table
ntable = Namespace.arel_table
pattern = "%#{query}%"
pattern = to_pattern(query)
......@@ -430,8 +429,6 @@
# unscoping unnecessary conditions that'll be applied
# when executing `where("projects.id IN (#{union.to_sql})")`
projects = unscoped.select(:id).where(
ptable[:path].matches(pattern)
.or(ptable[:name].matches(pattern))
.or(ptable[:description].matches(pattern))
where(
arel_table[:path].matches(pattern)
.or(arel_table[:name].matches(pattern))
.or(arel_table[:description].matches(pattern))
)
......@@ -437,12 +434,4 @@
)
namespaces = unscoped.select(:id)
.joins(:namespace)
.where(ntable[:name].matches(pattern))
union = Gitlab::SQL::Union.new([projects, namespaces])
where("projects.id IN (#{union.to_sql})") # rubocop:disable GitlabSecurity/SqlInjection
end
def search_by_title(query)
......@@ -446,10 +435,7 @@
end
def search_by_title(query)
pattern = "%#{query}%"
table = Project.arel_table
non_archived.where(table[:name].matches(pattern))
non_archived.where(arel_table[:name].matches(to_pattern(query)))
end
def visibility_levels
......
---
title: Drastically improve project search performance by no longer searching namespace
name
merge_request:
author:
type: performance
......@@ -30,7 +30,7 @@
def initialize(current_user, limit_projects, query)
@current_user = current_user
@limit_projects = limit_projects || Project.all
@query = Shellwords.shellescape(query) if query.present?
@query = query
end
def objects(scope, page = nil)
......
......@@ -136,7 +136,7 @@
context 'filter by name' do
let(:params) { { name: 'C' } }
it { is_expected.to match_array([shared_project, public_project, private_project]) }
it { is_expected.to match_array([public_project]) }
end
context 'sorting' do
......
......@@ -1254,24 +1254,6 @@
expect(described_class.search(project.path.upcase)).to eq([project])
end
it 'returns projects with a matching namespace name' do
expect(described_class.search(project.namespace.name)).to eq([project])
end
it 'returns projects with a partially matching namespace name' do
expect(described_class.search(project.namespace.name[0..2])).to eq([project])
end
it 'returns projects with a matching namespace name regardless of the casing' do
expect(described_class.search(project.namespace.name.upcase)).to eq([project])
end
it 'returns projects when eager loading namespaces' do
relation = described_class.all.includes(:namespace)
expect(relation.search(project.namespace.name)).to eq([project])
end
describe 'with pending_delete project' do
let(:pending_delete_project) { create(:project, pending_delete: true) }
......
......@@ -35,8 +35,8 @@
expect(results.objects('projects')).to match_array [internal_project, public_project]
end
it 'namespace name is searchable' do
results = described_class.new(user, search: found_project.namespace.path).execute
it 'project name is searchable' do
results = described_class.new(user, search: found_project.name).execute
expect(results.objects('projects')).to match_array [found_project]
end
......
Supports Markdown
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