混淆使用Rails.cache.fetch缓存Active Record查询

tin*_*ian 10 caching ruby-on-rails

我的版本是:

  • Rails: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
Run Code Online (Sandbox Code Playgroud)

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

 Rails.cache.fetch(key) do
     User.all
 end
Run Code Online (Sandbox Code Playgroud)

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

Sim*_*tti 33

原因是因为

User.where('status = 1').limit(1000)
Run Code Online (Sandbox Code Playgroud)

返回ActiveRecord::Relation实际上是范围而不是查询.Rails缓存范围.

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

Rails.cache.fetch(key) do
  User.where('status = 1').limit(1000).all
end
Run Code Online (Sandbox Code Playgroud)

请注意,缓存ActiveRecord对象绝不是一个好主意.缓存对象可能会导致状态和值不一致.在适用的情况下,应始终缓存基本对象.在这种情况下,请考虑缓存ID.

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

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

  • 我想要更多的证据表明,缓存ActiveRecords永远不是一个好主意(尽管如你所指出的那样,`find(ids)`的替代方法很快就会很快).特别是如果它们被用于显示目的的只读 - 可能是最常见的用法 - 我不确定它在大多数情况下会造成多大伤害.如果关联发生变化,可能存在链接断开的风险,需要进行逐案分析,但我认为这在现实中很少见. (2认同)