improves performance of work package autocompleter

* add db hint on mysql to use primary key for the ORDER BY
* restrict the fiels to search on based on the character of the search query. e.g. if there are alphabet characters in the search query, we don't have to search on the id column
pull/4020/head
Jens Ulferts 9 years ago
parent 4cfcdf3206
commit 2dfcd12abf
  1. 86
      app/controllers/work_packages/auto_completes_controller.rb

@ -29,37 +29,71 @@
require 'rack/utils'
class WorkPackages::AutoCompletesController < ApplicationController
class WorkPackages::AutoCompletesController < ::ApplicationController
before_filter :on_no_valid_scope_404
def index
@work_packages = work_package_with_id | work_packages_by_subject_or_id
respond_to do |format|
format.html do render layout: false end
format.any(:xml, :json) { render request.format.to_sym => wp_hashes_with_string(@work_packages) }
end
end
private
def on_no_valid_scope_404
scope = determine_scope
if scope.nil?
render_404
return
return false
end
end
def work_package_with_id
scope = determine_scope
query_term = params[:q].to_s
@work_packages = []
# query for exact ID matches first, to make an exact match the first result of autocompletion
if query_term =~ /\A\d+\z/
@work_packages |= scope.visible.where(id: query_term.to_i)
scope.visible.where(id: query_term.to_i)
else
[]
end
end
sql_query = ["LOWER(#{WorkPackage.table_name}.subject) LIKE :q OR
CAST(#{WorkPackage.table_name}.id AS CHAR(13)) LIKE :q",
{ q: "%#{query_term.downcase}%" }]
def work_packages_by_subject_or_id
scope = determine_scope
query_term = params[:q].to_s
@work_packages |= scope.visible
.where(sql_query)
.order("#{WorkPackage.table_name}.id ASC") # :id does not work because...
.limit(10)
if query_term =~ /\A\d+\z/
sql_query = ["#{WorkPackage.table_name}.subject LIKE :q OR
CAST(#{WorkPackage.table_name}.id AS CHAR(13)) LIKE :q",
{ q: "%#{query_term}%" }]
else
sql_query = ["LOWER(#{WorkPackage.table_name}.subject) LIKE :q",
{ q: "%#{query_term.downcase}%" }]
end
respond_to do |format|
format.html do render layout: false end
format.any(:xml, :json) { render request.format.to_sym => wp_hashes_with_string(@work_packages) }
# The filter on subject in combination with the ORDER BY on id
# seems to trip MySql's usage of indexes on the order statement
# I haven't seen similar problems on postgresql but there might be as the
# data at hand was not very large.
#
# For MySql we are therefore helping the DB optimizer to use the correct index
if ActiveRecord::Base.connection_config[:adapter] == 'mysql2'
scope = scope.from("#{WorkPackage.table_name} USE INDEX(PRIMARY)")
end
end
private
scope
.visible
.where(sql_query)
.order("#{WorkPackage.table_name}.id ASC") # :id does not work because...
.limit(10)
.includes(:type)
end
def wp_hashes_with_string(work_packages)
work_packages.map do |work_package|
@ -77,16 +111,18 @@ class WorkPackages::AutoCompletesController < ApplicationController
end
def determine_scope
project = find_project
@scope ||= begin
project = find_project
if params[:scope] == 'relatable'
return nil unless project
if params[:scope] == 'relatable'
return nil unless project
Setting.cross_project_work_package_relations? ? WorkPackage.all : project.work_packages
elsif params[:scope] == 'all' || project.nil?
WorkPackage.all
else
project.work_packages
Setting.cross_project_work_package_relations? ? WorkPackage.all : project.work_packages
elsif params[:scope] == 'all' || project.nil?
WorkPackage.all
else
project.work_packages
end
end
end
end

Loading…
Cancel
Save