避免在rails中进行mysql查询的策略

时间:2012-10-25 16:01:02

标签: mysql ruby-on-rails-3

我有一个应用程序(rails 3),它基本上是电视节目的社交网络。因此,用户可以与tv_shows进行互动。

每次显示users / tv_shows个人资料页面时,避免查询数据库(mysql)的最佳策略是什么?

例如:在电视节目简介页面中,我需要加载很多信息,如季节,剧集,演员等。要做到这一点,需要加入几个表,并且每天都变慢。

我的第一个想法是关于任何电视节目和存储的所有信息只在一个表中,所以我不需要每次都进行这些连接。

当然,我会有更好的表现但不是最好的。我知道那里有很多替代方案,比如memcache,redis甚至是mongodb但是这种情况的最佳方法是什么?

1 个答案:

答案 0 :(得分:1)

在我看来,最好的办法是为每个Show缓存一个编组对象,其中包含呈现页面所需的所有关系的预取数据。我使用Redis作为我的缓存,但你也可以使用Memcache或类似的东西。

shows = user.tv_shows.map do |show|
  if cached_show = $redis.get("shows:#{show.id}")
    # use the cached object
    Marshal.load(cached_show)
  else
    # cache has expired or was never created
    show.prefetch!
    # set the cache for the next visit and have it expire after +TIMEOUT+
    $redis.setnx("shows:#{show.id}", TIMEOUT, Marshal.dump(show))
    show
  end
end

在转储对象之前预取所有关系非常重要,否则在解组缓存对象后将打到数据库。

以下是预取的示例:

class Show
  def prefetch!
    @actors ||= actors
    self
  end

  def actors
    @actors || 1.upto(10).map do |n|
      Actor.new(n)
    end
  end
end

class Actor
  def initialize(n)
    puts "initialize actor #{n}"
  end
end

show = Show.new.prefetch!
cache = Marshal.dump(show)
Marshal.load(cache).actors.length  # uses value stored in @actors

show2 = Show.new
cache2 = Marshal.dump(show2)
Marshal.load(cache2).actors.length  # calls database