# QueryCache

**URL:** <https://www.ruby-forum.com/t/querycache/90009>\
**Category:** Rails\
**Created:** [March 24, 2007, 10:40pm UTC](https://www.ruby-forum.com/t/querycache/90009 "2007-03-24T22:40:59Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![Jens\_Himmelreich](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/j/7bcc69/32.png) [@Jens\_Himmelreich](https://www.ruby-forum.com/u/Jens_Himmelreich)\
**Post date:** [March 24, 2007, 10:40pm UTC](https://www.ruby-forum.com/t/querycache/90009/1 "2007-03-24T22:40:59Z")

</div>

Hi,

is someone interested in using the QueryCache?  
It seams to be an old part of rails. I enable  
the querycache in the database-specification with  
a:

query\_cache: true

and get an exception from ActiveRecord … ConnectionSpecification  
There is an if-clause, which did not work together with  
query\_cache (l. 247):

def self.connection=(spec) #:nodoc:  
if spec.kind\_of?(ActiveRecord::ConnectionAdapters::AbstractAdapter)  
active\_connections[name] = spec  
elsif spec.kind\_of?(ConnectionSpecification)  
config = spec.config.reverse\_merge(:allow\_concurrency =\>  
@@allow\_concurrency)  
self.connection = self.send(spec.adapter\_method, config)  
elsif spec.nil?  
raise ConnectionNotEstablished  
else  
establish\_connection spec  
end  
end

There is no clause for a QueryCache. But QueryCache acts like  
a connection. So I change it to:

```
if spec.kind_of?(ActiveRecord::ConnectionAdapters::AbstractAdapter) 

```

or  
spec.kind\_of?(ActiveRecord::QueryCache)

The next problem was the concurrency-model of rails. The QueryCache  
deletes  
all entries if an update, insert or delete-action was done. But most  
performance-sensitive enviroments use a few  
ruby/rails/mongrel-processes.  
So the QueryCache-Module isn’t scaleable.

In our Webshop we have different kinds of data. Some data, which isn’t  
changed at runtime (Categories, Products) and data, which will be  
changed by user-actions.

I add a class-method to ActiveRecord::base, so that you can specify  
your class as ‘cacheable’. Only this data will be cached. And I deleted  
the old update/insert/delete-semantic. Now the cache caches only  
‘cacheable’-classes. I add the rewrite of the query\_cache-File at the  
end of this mail.

The reason? Why? In the past I’m working with spring/hibernate-apps.  
There ist the ehcache, which boosts the performance. If the application  
don’t need to ask the database, it will be very fast. And because  
the ehcache ist between application-logic and database, you don’t  
had to think about caching. I had some experience with template-caching  
and it’s more intrusive.

With my few changes on the QueryCache, the performance will speed up  
from 4 Request per second to 6 requests per second. The database and  
the rails-app and the ab (apachebench) are on the same box. I hope  
the QueryCache will speed up more in an environment with the database  
on another box.

The next work will be the change of the datastructure for the cache.  
At the moment it’s a ruby-hash. You will get memory-problems, if there  
are many cacheable-entities in the cache. An LRU or LFU-Module will  
be better. It may be possible, to use a size-Parameter with the  
cacheable-call. Than every class could have its own cache-size.

we will see.  
jens

# query\_cache.rb

module ActiveRecord  
class QueryCache #:nodoc:  
def initialize(connection)  
@connection = connection  
@query\_cache = {}  
end

```
def clear_query_cache
  @query_cache = {}
end

def select_all(sql, name = nil)
  if ActiveRecord::Base.cacheable? extract_class(name)
    (@query_cache[sql] ||= @connection.select_all(sql, name)).dup
  else
    @connection.select_all(sql, name)
  end
end

def select_one(sql, name = nil)
  @query_cache[sql] ||= @connection.select_one(sql, name)
end

private
  def method_missing(method, *arguments, &proc)
    @connection.send(method, *arguments, &proc)
  end

  def extract_class name
    name ? name.split[0] : nil
  end

```

end

class Base  
@@cacheable\_classes = []  
# Set the connection for the class with caching on  
class \<\< self  
def cacheable  
@@cacheable\_classes \<\< self.name  
end

```
  def cacheable? name
    @@cacheable_classes.include? name
  end

  alias_method :connection_without_query_cache=, :connection=

  def connection=(spec)
    if spec.is_a?(ConnectionSpecification) and 

```

spec.config[:query\_cache]  
spec = QueryCache.new(self.send(spec.adapter\_method,  
spec.config))  
end  
self.connection\_without\_query\_cache = spec  
end  
end  
end

class AbstractAdapter #:nodoc:  
# Stub method to be able to treat the connection the same whether  
the query cache has been turned on or not  
def clear\_query\_cache  
end  
end  
end
