binarylogic / searchlogic

Searchlogic provides object based searching, common named scopes, and other useful tools.
http://rdoc.info/projects/binarylogic/searchlogic
MIT License
1.39k stars 133 forks source link

Searchlogic 2.4.22 generates a full table scan when :including associated models with a boolean column in a to_json call #108

Open ajsharp opened 14 years ago

ajsharp commented 14 years ago

Consider the following bloggish object model.

# has a boolean field called 'active'
class Content < ActiveRecord::Base
  has_many :categorizations
end

class Categorization < ActiveRecord::Base
  belongs_to :category
  belongs_to :content

  validates_presence_of :category_id, :content_id
end

Categorization.first.to_json(:include => :content)

# generates the following SQL queries
# Categorization Load (21.8ms)   SELECT * FROM "categorizations" LIMIT 1
# Content Load (0.4ms)   SELECT * FROM "contents" WHERE ("contents"."id" = 1) 
# Content Load (0.3ms)   SELECT * FROM "contents" WHERE ("contents"."active" = '1')

The last query, the full table scan, is not good. Especially if you have a large table and are trying to serialize all of them to json.

I'm not sure where/what is causing this, but I'll try to figure out what's going on here and submit a patch.

ajsharp commented 14 years ago

After stepping through rails, I've found that the additional query occurs here in activerecord/lib/serialization.rb:76. Specifically, this happens when rails tries to serialize the associated 'content' object. This is with active record 2.3.5.For convenience:

def serializable_record
  returning(serializable_record = {}) do
    serializable_names.each { |name| serializable_record[name] = @record.send(name) }
    add_includes do |association, records, opts|
      if records.is_a?(Enumerable)
        serializable_record[association] = records.collect { |r| self.class.new(r, opts).serializable_record }
      else
        serializable_record[association] = self.class.new(records, opts).serializable_record
      end
    end
  end
end
ajsharp commented 14 years ago

So it looks like every attribute being serialized during the to_json call is ending up in the send_with_searchlogic method in lib/searchlogic/active_record/association_proxy.rb:10 (http://github.com/binarylogic/searchlogic/blob/v2.4.22/lib/searchlogic/active_record/association_proxy.rb#L10).

The problem is that searchlogic automatically generates named scopes for all boolean columns, so when it hits this method with the active field, it calls proxy_reflection.klass.send(method, *args) on line 12, which I believe is generating the query.

Any ideas as to why a to_json call would end up here?