如何在Rails中缓存计算出的列? [英] How can I cache a calculated column in rails?

查看:57
本文介绍了如何在Rails中缓存计算出的列?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一棵活动记录对象树,像这样:

I have a tree of active record objects, something like:

class Part < ActiveRecord::Base
  has_many :sub_parts, :class_name => "Part"

  def complicated_calculation
    if sub_parts.size > 0
      return self.sub_parts.inject(0){ |sum, current| sum + current.complicated_calculation }
    else
      sleep(1)
      return rand(10000)
    end
  end

end

每次重新计算complex_calculation太昂贵。因此,我需要一种缓存值的方法。但是,如果更改了任何部分,则需要使其缓存以及其父代和祖父母代的缓存失效。

It is too costly to recalculate the complicated_calculation each time. So, I need a way to cache the value. However, if any part is changed, it needs to invalidate its cache and the cache of its parent, and grandparent, etc.

作为粗略的草稿,我创建了一个列将缓存的计算保存在部件表中,但这听起来有些烂。似乎应该有一种更干净的方法来缓存计算的值,而不会将其塞在真实列的旁边。

As a rough draft, I created a column to hold the cached calculation in the "parts" table, but this smells a little rotten. It seems like there should be a cleaner way to cache the calculated values without stuffing them along side the "real" columns.

推荐答案


  1. 您可以将实际缓存的值填充到Rails缓存中(如果需要分发,请使用memcached)。

  1. You can stuff the actually cached values in the Rails cache (use memcached if you require that it be distributed).

最棘手的是缓存过期,但是缓存过期并不常见,对吧?在这种情况下,我们可以依次循环遍历每个父对象并更改其缓存。我向您的班级添加了一些ActiveRecord魔术,以使父对象本身变得更加简单-甚至无需触摸数据库。请记住在您的代码中适当地调用 Part.sweep_complicated_cache(some_part) -您可以将其放入回调等中,但是我不能为您添加它,因为我没有

The tough bit is cache expiry, but cache expiry is uncommon, right? In that case, we can just loop over each of the parent objects in turn and zap its cache, too. I added some ActiveRecord magic to your class to make getting the parent objects simplicity itself -- and you don't even need to touch your database. Remember to call Part.sweep_complicated_cache(some_part) as appropriate in your code -- you can put this in callbacks, etc, but I can't add it for you because I don't understand when complicated_calculation is changing.

class Part < ActiveRecord::Base
  has_many :sub_parts, :class_name => "Part"
  belongs_to :parent_part, :class_name => "Part", :foreign_key => :part_id

  @@MAX_PART_NESTING = 25 #pick any sanity-saving value

  def complicated_calculation (...)
    if cache.contains? [id, :complicated_calculation]
      cache[ [id, :complicated_calculation] ]
    else
      cache[ [id, :complicated_calculation] ] = complicated_calculation_helper (...)
    end
  end

  def complicated_calculation_helper
    #your implementation goes here
  end

  def Part.sweep_complicated_cache(start_part)
    level = 1  # keep track to prevent infinite loop in event there is a cycle in parts
    current_part = self

    cache[ [current_part.id, :complicated_calculation] ].delete
    while ( (level <= 1 < @@MAX_PART_NESTING) && (current_part.parent_part)) {
     current_part = current_part.parent_part)
     cache[ [current_part.id, :complicated_calculation] ].delete
    end
  end
end


这篇关于如何在Rails中缓存计算出的列?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆