25

我网站上的数据库负载变得非常高,所以我是时候缓存那些每小时被调用 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 的调用不是 City.find(1) 而是 @user.city.name 其中 Rails 不使用 fetch 而是再次查询 DB ......这很有意义,但不完全是我想要的。

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

所以我的问题给你们。聪明人在做什么?这样做的正确方法是什么?

4

4 回答 4

23

关于缓存,有几点需要注意:

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

对 after_save 过滤器的一个小修正。由于您手头有数据,因此最好将其写回缓存而不是删除它。这为您节省了一次访问数据库的时间;)

def after_save
  Rails.cache.write(cache_key,self)
结尾

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

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

-或者-

  • 实现您的 User.fetch 方法以预先加载城市。仅当城市行的内容从未更改(即名称等)时才执行此操作,否则您可能会针对缓存失效打开一罐蠕虫。

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

我个人不是缓存模型样式插件的忠实拥护者,我从来没有见过一个可以节省大量开发时间的插件,而且我还没有匆忙摆脱。

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

于 2008-12-06T05:22:48.230 回答
1

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

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

在撰写本文时,matview 已在 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

于 2017-04-15T15:54:11.773 回答
0

我会继续看一下现在在 Rails 2.2 中的Memoization 。

“记忆化是一种将方法初始化一次,然后将其值隐藏起来以供重复使用的模式。”

最近有一个很棒的Railscast 插曲,它应该能让你很好地启动和运行。

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

更多关于记忆

于 2008-12-05T19:24:52.133 回答
-1

查看cached_model

于 2008-12-05T19:20:03.437 回答