]> source.dussan.org Git - redmine.git/commitdiff
Reduces the number of subqueries when searching with many custom fields set as search...
authorJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 5 Jan 2014 14:23:36 +0000 (14:23 +0000)
committerJean-Philippe Lang <jp_lang@yahoo.fr>
Sun, 5 Jan 2014 14:23:36 +0000 (14:23 +0000)
git-svn-id: http://svn.redmine.org/redmine/trunk@12481 e93f8b46-1217-0410-a6f0-8f06a7374b81

app/models/custom_field.rb
app/models/issue_custom_field.rb
lib/plugins/acts_as_searchable/lib/acts_as_searchable.rb

index b2c54d030ed94d87df9ba970a2b643122e1aa659..72ac471fd74b631f4667060d3ca8fbba44df7d54 100644 (file)
@@ -173,17 +173,18 @@ class CustomField < ActiveRecord::Base
     format.join_for_order_statement(self)
   end
 
-  def visibility_by_project_condition(project_key=nil, user=User.current)
+  def visibility_by_project_condition(project_key=nil, user=User.current, id_column=nil)
     if visible? || user.admin?
       "1=1"
     elsif user.anonymous?
       "1=0"
     else
       project_key ||= "#{self.class.customized_class.table_name}.project_id"
+      id_column ||= id
       "#{project_key} IN (SELECT DISTINCT m.project_id FROM #{Member.table_name} m" +
         " INNER JOIN #{MemberRole.table_name} mr ON mr.member_id = m.id" +
         " INNER JOIN #{table_name_prefix}custom_fields_roles#{table_name_suffix} cfr ON cfr.role_id = mr.role_id" +
-        " WHERE m.user_id = #{user.id} AND cfr.custom_field_id = #{id})"
+        " WHERE m.user_id = #{user.id} AND cfr.custom_field_id = #{id_column})"
     end
   end
 
index 513b96a5465a330341c0ea137b555d362ea68ea3..776bb4f0ac92db617fcefb3ce5f7cc123f3e01ff 100644 (file)
@@ -28,13 +28,14 @@ class IssueCustomField < CustomField
     super || (roles & user.roles_for_project(project)).present?
   end
 
-  def visibility_by_project_condition(*args)
+  def visibility_by_project_condition(project_key=nil, user=User.current, id_column=nil)
     sql = super
-    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})"
-    unless is_for_all?
-      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})"
-    end
-    "((#{sql}) AND (#{additional_sql}))"
+    id_column ||= id
+    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})"
+    project_condition = "EXISTS (SELECT 1 FROM #{CustomField.table_name} ifa WHERE ifa.is_for_all = #{connection.quoted_true} AND ifa.id = #{id_column})" + 
+      " 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})"
+
+    "((#{sql}) AND (#{tracker_condition}) AND (#{project_condition}))"
   end
 
   def validate_custom_field
index 3e91c72dc483e38d1a3dc2041e5e1d3b709d16de..dbdfa8992fdc8a15ea92e2e7006e1ae19a3d5d72 100644 (file)
@@ -82,11 +82,16 @@ module Redmine
 
             if !options[:titles_only] && searchable_options[:search_custom_fields]
               searchable_custom_fields = CustomField.where(:type => "#{self.name}CustomField", :searchable => true)
-              searchable_custom_fields.each do |field|
-                sql = "#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}" +
-                  " WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?" +
-                  " AND #{CustomValue.table_name}.custom_field_id = #{field.id})" +
-                  " AND #{field.visibility_by_project_condition(searchable_options[:project_key], user)}"
+              fields_by_visibility = searchable_custom_fields.group_by {|field|
+                field.visibility_by_project_condition(searchable_options[:project_key], user, "cfs.custom_field_id")
+              }
+              # only 1 subquery for all custom fields with the same visibility statement
+              fields_by_visibility.each do |visibility, fields|
+                ids = fields.map(&:id).join(',')
+                sql = "#{table_name}.id IN (SELECT cfs.customized_id FROM #{CustomValue.table_name} cfs" +
+                  " WHERE cfs.customized_type='#{self.name}' AND cfs.customized_id=#{table_name}.id AND LOWER(cfs.value) LIKE ?" +
+                  " AND cfs.custom_field_id IN (#{ids})" +
+                  " AND #{visibility})"
                 token_clauses << sql
               end
             end