2012-10-25 73 views
0

我有一个应用程序(导轨3),基本上是一个电视节目的社交网络。因此用户可以与其他人以及tv_shows进行交互。策略避免在查询轨道中的MySQL查询

每次显示用户/ tv_shows配置文件页面时,避免查询数据库(mysql)的最佳策略是什么?

例如:在电视节目的个人资料页面中,我需要加载许多信息,如季节,剧集,演员等。要做到这一点,需要加入多个表格,并且每天都变得越来越慢。

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

当然,我会有更好的表现,但不是最好的。我知道有很多像memcache,redis甚至mongodb这样的替代品,但对这种情况最好的办法是什么?

回答

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 
+0

感谢,我给它一个尝试,但怎么样的空间?我们超过30k的节目和近1M的节目。我不知道这需要多少空间。对于一个测试版项目来说这可能有点贵。 –

+0

在Redis中,可以设置“maxmemory”配置值。当达到'maxmemory'时,Redis将使用您指定的驱逐策略。在这种情况下,你会想指定'allkeys-lru'这将删除'最近最少使用'的密钥。这样,'hot'节目将保存在redis中,而其他节目将在'maxmemory'被击中时被删除。 'setex'也会在'TIMEOUT'秒后删除密钥。 https://github.com/antirez/redis/blob/unstable/redis.conf#l258-304 – lastcanal