11

我的版本是:

  • 导轨:3.2.6
  • 达利:2.1.0

我的环境是:

  • config.action_controller.perform_caching = true
  • config.cache_store = :dalli_store, 'localhost:11211', {:namespace => 'MyNameSpace'}

当我写:

 Rails.cache.fetch(key) do
     User.where('status = 1').limit(1000)
 end

无法缓存用户模型。如果我使用

 Rails.cache.fetch(key) do
     User.all
 end

它可以被缓存。如何缓存查询结果?

4

4 回答 4

38

原因是因为

User.where('status = 1').limit(1000)

返回ActiveRecord::Relation实际上是一个范围,而不是一个查询。Rails 缓存范围。

如果要缓存查询,则需要在末尾使用查询方法,例如#all.

Rails.cache.fetch(key) do
  User.where('status = 1').limit(1000).all
end

请注意,缓存 ActiveRecord 对象绝不是一个好主意。缓存对象可能会导致不一致的状态和值。如果适用,您应该始终缓存原始对象。在这种情况下,请考虑缓存 id。

ids = Rails.cache.fetch(key) do
  User.where('status = 1').limit(1000).pluck(:id)
end
User.find(ids)

User.find您可能会争辩说,在这种情况下,总是会执行对它的调用。确实如此,但是使用主键的查询速度很快,并且您可以解决我之前描述的问题。此外,缓存活动记录对象可能会很昂贵,并且您可能很快就会用一个缓存条目填满所有 Memcached 内存。缓存 id 也可以防止这个问题。

于 2012-06-27T07:21:11.923 回答
3

Rails.cache.fetch准确缓存块评估的内容。

 User.where('status = 1').limit(1000)

只是一个范围,所以缓存的只是 ActiveRecord::Relation 对象,即查询,而不是它的结果(因为查询尚未执行)。

如果你想缓存一些有用的东西,你需要在块内强制执行查询,例如通过做

User.where('status = 1').limit(1000).all

请注意,在 rails 4 上,all不会强制加载关系 -to_a改为使用

于 2012-06-27T07:14:31.897 回答
3

除了选定的答案:对于 Rails 4+,您应该使用load而不是all获取范围的结果。

于 2015-02-16T15:54:32.333 回答
0

使用

User.where("status = 1").limit(1000).all

应该管用。

于 2012-06-27T06:51:15.470 回答