Rails缓存数据库查询和最佳实践

时间:2008-12-05 18:29:21

标签: ruby-on-rails caching memcached

我网站上的数据库负载变得非常高,所以现在是时候缓存常见查询,这些查询每小时调用1000次,结果不会发生变化。 例如,在我的城市模型中,我执行以下操作:

def self.fetch(id)   
  Rails.cache.fetch("city_#{id}") { City.find(id) }   
end 

def after_save
  Rails.cache.delete("city_#{self.id}")
end

def after_destroy
  Rails.cache.delete("city_#{self.id}")
end

所以现在当我第一次点击数据库时可以使用City.find(1),但接下来的1000次我从内存中得到结果。大。但是大多数对城市的调用都不是City.find(1),而是@ user.city.name,其中Rails不使用fetch但是再次查询数据库......这有意义但不完全是我想要它做的。

我可以做City.find(@ user.city_id),但那很难看。

所以我向你们提问。聪明人在做什么?什么是 正确的方法吗?

4 个答案:

答案 0 :(得分:23)

关于缓存,有几个小问题:

值得使用斜杠来分隔对象类型和id,这是rails惯例。更好的是,ActiveRecord模型提供了cacke_key实例方法,该方法将提供表名和id的唯一标识符,“cities / 13”等。

对after_save过滤器进行一次小修正。由于您手头有数据,因此您可以将其写回缓存而不是删除它。这样可以省去一次数据库;)

def after_save
  Rails.cache.write(cache_key,self)
end

至于问题的根源,如果你不断拉@ user.city.name,有两个真正的选择:

  • 将用户的城市名称归一化为用户行。 @ user.city_name(保留city_id外键)。该值应在保存时写入。

- 或 -

  • 实施您的User.fetch方法以急切加载城市。只有在城市行的内容永远不会改变时才会这样做(即名称等),否则你可能会在缓存失效方面打开一堆蠕虫。

个人意见: 实现基于id的基本fetch方法(或使用插件)与memcached集成,并将城市名称反规范化为用户的行。

我个人并不是缓存模型风格插件的忠实粉丝,我从来没有见过一个节省了大量开发时间的插件,而我还没有匆忙成长。

如果你的数据库查询过多,那么如果你还没有,那么绝对值得检查出急切加载(通过:include)。这应该是减少数据库查询数量的第一步。

答案 1 :(得分:0)

我会继续看看Memoization,现在在Rails 2.2中。

  

“记忆是一种模式   一次初始化方法然后   把它的价值藏起来重复一遍   用“。

最近它上面有一个很棒的Railscast episode,可以让你很好地运行。

来自Railscast的快速代码示例:

class Product < ActiveRecord::Base
  extend ActiveSupport::Memoizable

  belongs_to :category

  def filesize(num = 1)
    # some expensive operation
    sleep 2
    12345789 * num
  end
  memoize :filesize
end

More on Memoization

答案 2 :(得分:0)

如果您需要加快对不会随时间变化很大的数据的SQL查询,那么您可以使用物化视图。

  

matview将查询结果存储到类似于表的结构中   它自己的,可以从中查询数据。无法添加   或删除行,但其余时间它的行为就像一个   实际的表。查询更快,matview本身也可以   索引。

     

在撰写本文时,matviews在Oracle中可以原生使用   DB,PostgreSQL,Sybase,IBM DB2和Microsoft SQL Server。 MySQL的   不幸的是,它没有为matviews提供原生支持   是它的开源替代品。

以下是一些关于如何在Rails中使用matviews的好文章

sitepoint.com/speed-up-with-materialized-views-on-postgresql-and-rails

hashrocket.com/materialized-view-strategies-using-postgresql

答案 3 :(得分:-1)

查看cached_model