##// END OF EJS Templates
Reduces the number of subqueries when searching with many custom fields set as searchable (#15781)....
Jean-Philippe Lang -
r12206:77ac3b7891d4
parent child
Show More
@@ -173,17 +173,18 class CustomField < ActiveRecord::Base
173 format.join_for_order_statement(self)
173 format.join_for_order_statement(self)
174 end
174 end
175
175
176 def visibility_by_project_condition(project_key=nil, user=User.current)
176 def visibility_by_project_condition(project_key=nil, user=User.current, id_column=nil)
177 if visible? || user.admin?
177 if visible? || user.admin?
178 "1=1"
178 "1=1"
179 elsif user.anonymous?
179 elsif user.anonymous?
180 "1=0"
180 "1=0"
181 else
181 else
182 project_key ||= "#{self.class.customized_class.table_name}.project_id"
182 project_key ||= "#{self.class.customized_class.table_name}.project_id"
183 id_column ||= id
183 "#{project_key} IN (SELECT DISTINCT m.project_id FROM #{Member.table_name} m" +
184 "#{project_key} IN (SELECT DISTINCT m.project_id FROM #{Member.table_name} m" +
184 " INNER JOIN #{MemberRole.table_name} mr ON mr.member_id = m.id" +
185 " INNER JOIN #{MemberRole.table_name} mr ON mr.member_id = m.id" +
185 " INNER JOIN #{table_name_prefix}custom_fields_roles#{table_name_suffix} cfr ON cfr.role_id = mr.role_id" +
186 " INNER JOIN #{table_name_prefix}custom_fields_roles#{table_name_suffix} cfr ON cfr.role_id = mr.role_id" +
186 " WHERE m.user_id = #{user.id} AND cfr.custom_field_id = #{id})"
187 " WHERE m.user_id = #{user.id} AND cfr.custom_field_id = #{id_column})"
187 end
188 end
188 end
189 end
189
190
@@ -28,13 +28,14 class IssueCustomField < CustomField
28 super || (roles & user.roles_for_project(project)).present?
28 super || (roles & user.roles_for_project(project)).present?
29 end
29 end
30
30
31 def visibility_by_project_condition(*args)
31 def visibility_by_project_condition(project_key=nil, user=User.current, id_column=nil)
32 sql = super
32 sql = super
33 additional_sql = "#{Issue.table_name}.tracker_id IN (SELECT tracker_id FROM #{table_name_prefix}custom_fields_trackers#{table_name_suffix} WHERE custom_field_id = #{id})"
33 id_column ||= id
34 unless is_for_all?
34 tracker_condition = "#{Issue.table_name}.tracker_id IN (SELECT tracker_id FROM #{table_name_prefix}custom_fields_trackers#{table_name_suffix} WHERE custom_field_id = #{id_column})"
35 additional_sql << " AND #{Issue.table_name}.project_id IN (SELECT project_id FROM #{table_name_prefix}custom_fields_projects#{table_name_suffix} WHERE custom_field_id = #{id})"
35 project_condition = "EXISTS (SELECT 1 FROM #{CustomField.table_name} ifa WHERE ifa.is_for_all = #{connection.quoted_true} AND ifa.id = #{id_column})" +
36 end
36 " OR #{Issue.table_name}.project_id IN (SELECT project_id FROM #{table_name_prefix}custom_fields_projects#{table_name_suffix} WHERE custom_field_id = #{id_column})"
37 "((#{sql}) AND (#{additional_sql}))"
37
38 "((#{sql}) AND (#{tracker_condition}) AND (#{project_condition}))"
38 end
39 end
39
40
40 def validate_custom_field
41 def validate_custom_field
@@ -82,11 +82,16 module Redmine
82
82
83 if !options[:titles_only] && searchable_options[:search_custom_fields]
83 if !options[:titles_only] && searchable_options[:search_custom_fields]
84 searchable_custom_fields = CustomField.where(:type => "#{self.name}CustomField", :searchable => true)
84 searchable_custom_fields = CustomField.where(:type => "#{self.name}CustomField", :searchable => true)
85 searchable_custom_fields.each do |field|
85 fields_by_visibility = searchable_custom_fields.group_by {|field|
86 sql = "#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}" +
86 field.visibility_by_project_condition(searchable_options[:project_key], user, "cfs.custom_field_id")
87 " WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?" +
87 }
88 " AND #{CustomValue.table_name}.custom_field_id = #{field.id})" +
88 # only 1 subquery for all custom fields with the same visibility statement
89 " AND #{field.visibility_by_project_condition(searchable_options[:project_key], user)}"
89 fields_by_visibility.each do |visibility, fields|
90 ids = fields.map(&:id).join(',')
91 sql = "#{table_name}.id IN (SELECT cfs.customized_id FROM #{CustomValue.table_name} cfs" +
92 " WHERE cfs.customized_type='#{self.name}' AND cfs.customized_id=#{table_name}.id AND LOWER(cfs.value) LIKE ?" +
93 " AND cfs.custom_field_id IN (#{ids})" +
94 " AND #{visibility})"
90 token_clauses << sql
95 token_clauses << sql
91 end
96 end
92 end
97 end
General Comments 0
You need to be logged in to leave comments. Login now