My version is:
My env is:
When I write:
Rails.cache.fetch(key) do
User.where('status = 1').limit(1000)
end
The user model can't be cached. If I use
Rails.cache.fetch(key) do
User.all
end
it can be cached. How to cache query result?
Query caching is a Rails feature that caches the result set returned by each query. If Rails encounters the same query again for that request, it will use the cached result set as opposed to running the query against the database again.
Rails 5.2 introduced built-in Redis cache store, which allows you to store cache entries in Redis.
To avoid it, Rails provides with the schema cache feature. The idea is: Serialize data about the schema (tables, columns, and types) into a file. Distribute that file over all application servers. Load the data from file to avoid hitting the database.
In computing, a cache is a high-speed data storage layer which stores a subset of data, typically transient in nature, so that future requests for that data are served up faster than is possible by accessing the data's primary storage location.
The reason is because
User.where('status = 1').limit(1000)
returns an ActiveRecord::Relation
which is actually a scope, not a query. Rails caches the scope.
If you want to cache the query, you need to use a query method at the end, such as #all
.
Rails.cache.fetch(key) do
User.where('status = 1').limit(1000).all
end
Please note that it's never a good idea to cache ActiveRecord objects. Caching an object may result in inconsistent states and values. You should always cache primitive objects, when applicable. In this case, consider to cache the ids.
ids = Rails.cache.fetch(key) do
User.where('status = 1').limit(1000).pluck(:id)
end
User.find(ids)
You may argue that in this case a call to User.find
it's always executed. It's true, but the query using primary key is fast and you get around the problem I described before. Moreover, caching active record objects can be expensive and you might quickly end up filling all Memcached memory with just one single cache entry. Caching ids will prevent this problem as well.
In addition to selected answer: for Rails 4+ you should use load
instead of all
for getting the result of scope.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With