我网站上的数据库负载变得非常高,所以现在是时候缓存常见查询,这些查询每小时调用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),但那很难看。
所以我向你们提问。聪明人在做什么?什么是 正确的方法吗?
答案 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,有两个真正的选择:
- 或 -
个人意见: 实现基于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
答案 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)