Improve AutocompleteController#user.json performance

This commit is contained in:
Hiroyuki Sato 2017-08-23 01:51:53 +09:00
parent 539ed0a637
commit 9e203582b3
6 changed files with 89 additions and 7 deletions

View File

@ -303,7 +303,7 @@ class User < ActiveRecord::Base
# Returns an ActiveRecord::Relation.
def search(query)
table = arel_table
pattern = "%#{query}%"
pattern = Gitlab::SQL::Pattern.new(query).to_sql
order = <<~SQL
CASE

View File

@ -0,0 +1,5 @@
---
title: Improve performance for AutocompleteController#users.json
merge_request: 13754
author: Hiroyuki Sato
type: changed

29
lib/gitlab/sql/pattern.rb Normal file
View File

@ -0,0 +1,29 @@
module Gitlab
module SQL
class Pattern
MIN_CHARS_FOR_PARTIAL_MATCHING = 3
attr_reader :query
def initialize(query)
@query = query
end
def to_sql
if exact_matching?
query
else
"%#{query}%"
end
end
def exact_matching?
!partial_matching?
end
def partial_matching?
@query.length >= MIN_CHARS_FOR_PARTIAL_MATCHING
end
end
end
end

View File

@ -6,7 +6,7 @@ describe 'Dropdown author', js: true do
let!(:project) { create(:project) }
let!(:user) { create(:user, name: 'administrator', username: 'root') }
let!(:user_john) { create(:user, name: 'John', username: 'th0mas') }
let!(:user_jacob) { create(:user, name: 'Jacob', username: 'otter32') }
let!(:user_jacob) { create(:user, name: 'Jacob', username: 'ooter32') }
let(:filtered_search) { find('.filtered-search') }
let(:js_dropdown_author) { '#js-dropdown-author' }
@ -82,31 +82,31 @@ describe 'Dropdown author', js: true do
end
it 'filters by name' do
send_keys_to_filtered_search('ja')
send_keys_to_filtered_search('jac')
expect(dropdown_author_size).to eq(1)
end
it 'filters by case insensitive name' do
send_keys_to_filtered_search('Ja')
send_keys_to_filtered_search('Jac')
expect(dropdown_author_size).to eq(1)
end
it 'filters by username with symbol' do
send_keys_to_filtered_search('@ot')
send_keys_to_filtered_search('@oot')
expect(dropdown_author_size).to eq(2)
end
it 'filters by username without symbol' do
send_keys_to_filtered_search('ot')
send_keys_to_filtered_search('oot')
expect(dropdown_author_size).to eq(2)
end
it 'filters by case insensitive username without symbol' do
send_keys_to_filtered_search('OT')
send_keys_to_filtered_search('OOT')
expect(dropdown_author_size).to eq(2)
end

View File

@ -0,0 +1,31 @@
require 'spec_helper'
describe Gitlab::SQL::Pattern do
describe '#to_sql' do
subject(:to_sql) { described_class.new(query).to_sql }
context 'when a query is shorter than 3 chars' do
let(:query) { '12' }
it 'returns exact matching pattern' do
expect(to_sql).to eq('12')
end
end
context 'when a query is equal to 3 chars' do
let(:query) { '123' }
it 'returns partial matching pattern' do
expect(to_sql).to eq('%123%')
end
end
context 'when a query is longer than 3 chars' do
let(:query) { '1234' }
it 'returns partial matching pattern' do
expect(to_sql).to eq('%1234%')
end
end
end
end

View File

@ -789,6 +789,7 @@ describe User do
describe '.search' do
let!(:user) { create(:user, name: 'user', username: 'usern', email: 'email@gmail.com') }
let!(:user2) { create(:user, name: 'user name', username: 'username', email: 'someemail@gmail.com') }
let!(:user3) { create(:user, name: 'us', username: 'se', email: 'foo@gmail.com') }
describe 'name matching' do
it 'returns users with a matching name with exact match first' do
@ -802,6 +803,14 @@ describe User do
it 'returns users with a matching name regardless of the casing' do
expect(described_class.search(user2.name.upcase)).to eq([user2])
end
it 'returns users with a exact matching name shorter than 3 chars' do
expect(described_class.search(user3.name)).to eq([user3])
end
it 'returns users with a exact matching name shorter than 3 chars regardless of the casing' do
expect(described_class.search(user3.name.upcase)).to eq([user3])
end
end
describe 'email matching' do
@ -830,6 +839,14 @@ describe User do
it 'returns users with a matching username regardless of the casing' do
expect(described_class.search(user2.username.upcase)).to eq([user2])
end
it 'returns users with a exact matching username shorter than 3 chars' do
expect(described_class.search(user3.username)).to eq([user3])
end
it 'returns users with a exact matching username shorter than 3 chars regardless of the casing' do
expect(described_class.search(user3.username.upcase)).to eq([user3])
end
end
end