41bfe82b7a
This optimises searching for users when using queries consisting out of one or two characters such as "ab". We optimise such cases by searching for `LOWER(name)` and `LOWER(username)` instead of using `ILIKE`. Using `LOWER` produces a _much_ better performing query. For example, when searching for all users matching the term "a" we'd produce the following plan: Limit (cost=637.69..637.74 rows=20 width=805) (actual time=41.983..41.995 rows=20 loops=1) Buffers: shared hit=8330 -> Sort (cost=637.69..638.61 rows=368 width=805) (actual time=41.982..41.990 rows=20 loops=1) Sort Key: (CASE WHEN ((name)::text = 'a'::text) THEN 0 WHEN ((username)::text = 'a'::text) THEN 1 WHEN ((email)::text = 'a'::text) THEN 2 ELSE 3 END), name Sort Method: top-N heapsort Memory: 35kB Buffers: shared hit=8330 -> Bitmap Heap Scan on users (cost=75.47..627.89 rows=368 width=805) (actual time=9.452..41.305 rows=277 loops=1) Recheck Cond: (((name)::text ~~* 'a'::text) OR ((username)::text ~~* 'a'::text) OR ((email)::text = 'a'::text)) Rows Removed by Index Recheck: 7601 Heap Blocks: exact=7636 Buffers: shared hit=8327 -> BitmapOr (cost=75.47..75.47 rows=368 width=0) (actual time=8.290..8.290 rows=0 loops=1) Buffers: shared hit=691 -> Bitmap Index Scan on index_users_on_name_trigram (cost=0.00..38.85 rows=180 width=0) (actual time=4.369..4.369 rows=4071 loops=1) Index Cond: ((name)::text ~~* 'a'::text) Buffers: shared hit=360 -> Bitmap Index Scan on index_users_on_username_trigram (cost=0.00..34.41 rows=188 width=0) (actual time=3.896..3.896 rows=4140 loops=1) Index Cond: ((username)::text ~~* 'a'::text) Buffers: shared hit=328 -> Bitmap Index Scan on users_email_key (cost=0.00..1.94 rows=1 width=0) (actual time=0.022..0.022 rows=0 loops=1) Index Cond: ((email)::text = 'a'::text) Buffers: shared hit=3 Planning time: 3.912 ms Execution time: 42.171 ms With the changes in this commit we now produce the following plan instead: Limit (cost=13257.48..13257.53 rows=20 width=805) (actual time=1.567..1.579 rows=20 loops=1) Buffers: shared hit=287 -> Sort (cost=13257.48..13280.93 rows=9379 width=805) (actual time=1.567..1.572 rows=20 loops=1) Sort Key: (CASE WHEN ((name)::text = 'a'::text) THEN 0 WHEN ((username)::text = 'a'::text) THEN 1 WHEN ((email)::text = 'a'::text) THEN 2 ELSE 3 END), name Sort Method: top-N heapsort Memory: 35kB Buffers: shared hit=287 -> Bitmap Heap Scan on users (cost=135.66..13007.91 rows=9379 width=805) (actual time=0.194..1.107 rows=277 loops=1) Recheck Cond: ((lower((name)::text) = 'a'::text) OR (lower((username)::text) = 'a'::text) OR ((email)::text = 'a'::text)) Heap Blocks: exact=277 Buffers: shared hit=287 -> BitmapOr (cost=135.66..135.66 rows=9379 width=0) (actual time=0.152..0.152 rows=0 loops=1) Buffers: shared hit=10 -> Bitmap Index Scan on yorick_test_users (cost=0.00..124.75 rows=9377 width=0) (actual time=0.101..0.101 rows=277 loops=1) Index Cond: (lower((name)::text) = 'a'::text) Buffers: shared hit=4 -> Bitmap Index Scan on index_on_users_lower_username (cost=0.00..1.94 rows=1 width=0) (actual time=0.035..0.035 rows=1 loops=1) Index Cond: (lower((username)::text) = 'a'::text) Buffers: shared hit=3 -> Bitmap Index Scan on users_email_key (cost=0.00..1.94 rows=1 width=0) (actual time=0.014..0.014 rows=0 loops=1) Index Cond: ((email)::text = 'a'::text) Buffers: shared hit=3 Planning time: 0.303 ms Execution time: 1.687 ms Here we can see the new query is 25 times faster compared to the old query. |
||
---|---|---|
.. | ||
auth | ||
background_migration | ||
badge | ||
bare_repository_import | ||
bitbucket_import | ||
cache | ||
checks | ||
ci | ||
conflict | ||
cycle_analytics | ||
data_builder | ||
database | ||
dependency_linker | ||
diff | ||
downtime_check | ||
etag_caching | ||
fogbugz_import | ||
gfm | ||
git | ||
gitaly_client | ||
github_import | ||
gitlab_import | ||
google_code_import | ||
gpg | ||
grape_logging | ||
graphs | ||
health_checks | ||
hook_data | ||
i18n | ||
import_export | ||
kubernetes | ||
ldap | ||
legacy_github_import | ||
metrics | ||
middleware | ||
o_auth | ||
performance_bar | ||
popen | ||
project_authorizations | ||
prometheus | ||
query_limiting | ||
quick_actions | ||
redis | ||
request_profiler | ||
saml | ||
sanitizers | ||
serializer | ||
sherlock | ||
sidekiq_middleware | ||
sidekiq_status | ||
sidekiq_versioning | ||
slash_commands | ||
sql | ||
storage_check | ||
template | ||
testing | ||
utils | ||
view/presenter | ||
access.rb | ||
action_rate_limiter.rb | ||
allowable.rb | ||
app_logger.rb | ||
asciidoc.rb | ||
auth.rb | ||
background_migration.rb | ||
blame.rb | ||
changes_list.rb | ||
chat_name_token.rb | ||
ci_access.rb | ||
closing_issue_extractor.rb | ||
color_schemes.rb | ||
config_helper.rb | ||
contributions_calendar.rb | ||
contributor.rb | ||
current_settings.rb | ||
daemon.rb | ||
database.rb | ||
dependency_linker.rb | ||
downtime_check.rb | ||
ee_compat_check.rb | ||
emoji.rb | ||
encoding_helper.rb | ||
environment.rb | ||
environment_logger.rb | ||
exclusive_lease.rb | ||
fake_application_settings.rb | ||
file_detector.rb | ||
file_finder.rb | ||
git.rb | ||
git_access.rb | ||
git_access_wiki.rb | ||
git_logger.rb | ||
git_post_receive.rb | ||
git_ref_validator.rb | ||
gitaly_client.rb | ||
github_import.rb | ||
gl_id.rb | ||
gl_repository.rb | ||
gon_helper.rb | ||
gpg.rb | ||
group_hierarchy.rb | ||
highlight.rb | ||
i18n.rb | ||
identifier.rb | ||
import_export.rb | ||
import_formatter.rb | ||
import_sources.rb | ||
incoming_email.rb | ||
insecure_key_fingerprint.rb | ||
issuable_metadata.rb | ||
issuable_sorter.rb | ||
issuables_count_for_state.rb | ||
issues_labels.rb | ||
job_waiter.rb | ||
kubernetes.rb | ||
lazy.rb | ||
lfs_token.rb | ||
logger.rb | ||
mail_room.rb | ||
markup_helper.rb | ||
metrics.rb | ||
multi_collection_paginator.rb | ||
o_auth.rb | ||
optimistic_locking.rb | ||
other_markup.rb | ||
otp_key_rotator.rb | ||
pages.rb | ||
pages_transfer.rb | ||
path_regex.rb | ||
performance_bar.rb | ||
polling_interval.rb | ||
popen.rb | ||
profiler.rb | ||
project_search_results.rb | ||
project_template.rb | ||
project_transfer.rb | ||
prometheus_client.rb | ||
protocol_access.rb | ||
query_limiting.rb | ||
recaptcha.rb | ||
reference_counter.rb | ||
reference_extractor.rb | ||
regex.rb | ||
repo_path.rb | ||
repository_check_logger.rb | ||
request_context.rb | ||
request_forgery_protection.rb | ||
request_profiler.rb | ||
route_map.rb | ||
routing.rb | ||
search_results.rb | ||
seeder.rb | ||
sentry.rb | ||
setup_helper.rb | ||
shell.rb | ||
shell_adapter.rb | ||
sherlock.rb | ||
sidekiq_config.rb | ||
sidekiq_logger.rb | ||
sidekiq_status.rb | ||
sidekiq_throttler.rb | ||
sidekiq_versioning.rb | ||
snippet_search_results.rb | ||
ssh_public_key.rb | ||
storage_check.rb | ||
string_range_marker.rb | ||
string_regex_marker.rb | ||
task_helpers.rb | ||
tcp_checker.rb | ||
themes.rb | ||
time_tracking_formatter.rb | ||
timeless.rb | ||
untrusted_regexp.rb | ||
update_path_error.rb | ||
upgrader.rb | ||
uploads_transfer.rb | ||
url_blocker.rb | ||
url_builder.rb | ||
url_sanitizer.rb | ||
usage_data.rb | ||
user_access.rb | ||
user_activities.rb | ||
utils.rb | ||
version_info.rb | ||
visibility_level.rb | ||
workhorse.rb |