Rails复杂查询结果的短期缓存

时间:2013-10-17 23:58:09

标签: ruby-on-rails caching optimization

special_item_id_list方法负责返回一组id。查询和逻辑足够复杂,我只想在每个页面请求中运行一次,但我会在许多不同的地方使用生成的id数组。我们的想法是能够自由地使用is_special?方法或special_items范围,而不必担心每次使用时都会产生开销,因此他们依靠special_item_id_list方法来做重提升和缓存。

我不希望此查询的结果在页面加载之间保持不变,但我希望每次加载时查询只运行一次。我不想使用全局变量,并认为模型上的类变量可能有效,但看起来类变量在页面加载之间保持不变。我猜测Item类是Rails堆栈的一部分并保留在内存中。

那么在哪里存储我的id列表的首选位置,以便在每次加载页面时重建它?

class Item < ActiveRecord::Base

  scope :special_items, lambda { where(:id => special_item_id_list) }

  def self.special_item_id_list
    @special_item_id_list ||= ... # some complicated queries
  end

  def is_special?
    self.class.special_item_id_list.include?(id)
  end

end

更新:使用Thread怎么样?我之前已经完成了跟踪当前用户的操作,我认为它可以在这里应用,但我想知道是否还有另一种方法?这是StackOverflow conversation discussing threads!并且还提到了request_store!宝石可能是一种更清洁的方式。

3 个答案:

答案 0 :(得分:1)

This railscast涵盖了您正在寻找的内容。简而言之,你会想要做这样的事情:

after_commit :flush_cache

def self.cached_special_item_list
  Rails.cache.fetch("special_items") do
    special_item_id_list
  end
end

private

def flush_cache
  Rails.cache.delete("special_items")
end

答案 1 :(得分:1)

起初,我采用了Jonathan Bender关于利用Rails.cache(感谢John)的建议,但对我如何使其过期感到不满意。由于缺乏更好的想法,我认为最好使用Thread。我最终安装了request_store gem来存储查询结果。这样可以保持数据的持续时间(请求/响应的生命周期),不再需要过期。

答案 2 :(得分:0)

你真的确定这种优化是必要的吗?您是否因此而遇到性能问题?除非它实际上是一个问题,否则我不会担心它。

那说;您可以创建一个新类,在该类上创建special_item_id_list实例方法,然后将该类传递给需要使用这些昂贵的计算数据的任何内容。

或者将数据缓存在Item的实例上可能就足够了(可能通过使special_item_id_list成为实例方法),而不必担心不能共享缓存的不同实例。