ActiveRecord
is the default object relational model of the Rails web framework. It obviously follows the
active record architectural pattern. Now,
ActiveRecord
maintains it own query cache which is different from the query cache of the underlying database server. This query cache is a rather simplistic one.
The issue that brought the requirement of query cache bypassing into picture was as follows.
1. a call to first object of the model to check if any records existed (Model.first)
2. raw SQL query to truncate the table
3. a call again to first object of the model to check if any records existed (Model.first)
Now, #1 and #3 obviously generated same SQL query. So,
ActiveRecord
served #3 from its cache.
We found multiple approaches of bypassing the
ActiveRecord
cache.
Approach 1
Clear the entire
ActiveRecord
cache. In Rails 2 this can be done using
ActiveRecord::Base.query_cache.clear_query_cache
In Rails 3, the same can be achieved using the following line.
ActiveRecord::Base.connection.clear_query_cache
This approach however would clear the entire
ActiveRecord
cache which in production environment means increasing load on database server which is already the bottleneck. Plus, this approach is like using a jack hammer where a finger-tap would work.
Approach 2
This approach exploits the simplicity of the
ActiveRecord
cache. It forms the query in such a manner that the query string is very likely to be different from previous queries.
r = call random number generator
where_clause = "r = r"
Appending the above where clause to #1 and #3, we obtained queries that are very likely to be different from previous ones at least within the life time of the cache. This approach is obviously not elegant.
Approach 3
In this approach, we went with raw SQL queries not only for #2 but also for #1 and #3.
ActiveRecord
does not seem to cache raw SQL queries. So we could replace the call to the 'first' method of the model with something similar to the following.
sql = "select * from table_name limit 1"
ActiveRecord::Base.connection.execute sql
Although we can get the job done by this approach, it is bad practice to execute raw SQL.
Approach 4
Finally, we found a way of doing it through Rails. We need to explicitly tell Rails not to serve our queries from its cache for #1 and #3. This can be done as follows.
Model.uncached do
Model.first
end
As this method does the job using the Rails framework, the abstraction all provided by ActiveRecord remains unbroken.