打印

model级别cache的(一)

本帖已经被作者加入个人空间

model级别cache的(一)

数据库是瓶颈,今天我们介绍model级别的cache。Cached Model 是一个简单的只对单记录做缓存的plugin.Cached Model的的存储分为本地存储和Memcached存储。本地存储大家都知道,一般都是用Hash来存储的。这里的Memcached是一种网络分布式存储。

我们先来看看如果应用cached model
一:安装

gem install cached_model -y


二:应用
简单的创建一个工程

php?name=rails" onclick="tagshow(event)" class="t_tag">rails cached_model_demo


新建Page

ruby script/generate scaffold_resource page title:string content:text created_at:timestamp


创建数据库

rake db:migrate


修改Page Model,继承CachedModel

class Page < CachedModel
end


在enviroment中增加memcached的配置的代码:

require 'cached_model'

memcache_options = {
  :c_threshold => 10_000,
  :compression => true,
  :debug => false,
  :namespace => 'cached_model_demo',
  :readonly => false,
  :urlencode => false
}

CACHE = MemCache.new memcache_options
CACHE.servers = 'localhost:11211'


上面都是一些简单的东西,我们就忽略了,有什么问题,大家提出来。

好了,准备就绪。cached_model 默认是采用memcached store的方式,当然你可以采用local的方式

CachedModel::use_local_cache=true


启动memcached server

memcached -vv


我们传递vv参数可以查看更多的日志信息,具体的可以查看--help


打开ruby script/console 并打开tail -f log/development.log查看日志
新建page

Page.create :title=>'Hello World'
Page.create :title=>'Hello World Again'


成功。cached_model只覆盖了ActiveRecord的两个方法,一个是find,一个是find_by_sql.我们具体的分析一下这两个方法
1:) find

 def self.find(*args)
        args[0] = args.first.to_i if args.first =~ /\A\d+\Z/
        # Only handle simple find requests.  If the request was more complicated,
        # let the base class handle it, but store the retrieved records in the
        # local cache in case we need them later.        
        if args.length != 1 || !Fixnum === args.first then
            # Rails requires multiple levels of indirection to look up a record
            # First call super
            records = super
            # Then, if it was a :all, just return
            return records if args.first == :all
            return records if RAILS_ENV == 'test'
            case records
            when Array then
                records.each { |r| r.cache_store }
            end
            return records
        end

        return super
    end


这里面压根没有读取cache的代码,不管这么样,都会先调用super执行查询,只有在
>参数个数不为1或第一个不是数字
>第一个参数不是:all
>不是test环境下
>返回结果为Array的时候才缓存model 
也就是说基本没什么作用。
我们试验下

Page.find 1


依然执行SQL,memcached无反应

Page.find 1,2


我们会看到memcached中有了两条记录

<1924 new client connection
<1924 set cached_model_demo:active_record:Page:1 0 900 95
>1924 STORED
<1924 set cached_model_demo:active_record:Page:2 0 900 101
>1924 STORED


保存了两条记录

在执行

Page.find 1


依然查询数据库。那我们该如何取这样的数据呢?

>> Cache.get "active_record:Page:1"
=> #"Hello World", "id"=>"1", "content"=>nil, "cr
ed_at"=>"2007-11-10 18:29:29"}>


2:)find_by_sql

 def self.find_by_sql(*args)
        return super unless args.first =~ /^SELECT \* FROM #{table_name} WHERE \(?#{table_name}\.#{primary_key} = '?(\d+)'?\)? +LIMIT 1/


很简单,但是他只cache根据主键id查询的record

Page.find_by_sql "SELECT * FROM PAGES WHERE PAGES.ID = 1 LIMIT 1"




<1924 get cached_model_demo:active_record:Page:1
>1924 sending key cached_model_demo:active_record:Page:1
>1924 END


development.log无SQL查询

MemCache Get (0.000000)  active_record:Page:1


这里取回的是我们刚才执行Page.find 1,2,缓存1的数据,如果没有,则会存储该数据,下次再查询直接从cache中获取。

三:更新
当该id的记录update,destroy都会更新cache,这个没什么好说的。

四:改进
这些功能太过于简单了,我们可以稍微对源码做点修改
一:缓存Page.find 的单条记录

if CachedModel.use_memcache?
        record = Cache.get "active_record:#{name}:#{args.first}"

        #return cached model
        return record unless record.nil?
        #call super find
        record = super
        #store in memcache
        record.cache_store

        return record
      end
    end


二:find_by_sql的改进,空格,大小写必须一致才能生效
这条正则表达式太过于简单,我们可以稍微修改
1:) 忽略大小写 /i
2:) 忽略table的名称,只需要id=?几匹配
2;) 忽略空格


警告:
对于有关联的Model请谨慎使用cached_model,建议不使用。

[ 本帖最后由 martin 于 2007-11-12 09:38 编辑 ]
本帖最近评分记录
  • blackanger R币 +5 我很赞同 2007-11-24 17:08
  • bayerlin R币 +3 精品文章 2007-11-18 01:33
  • skyover R币 +3 精品文章 2007-11-16 19:11
  • drive2me R币 +3 好分享! 2007-11-16 15:33
  • axgle R币 +3 原创内容 2007-11-16 11:51

TOP

本文有没有必要放到还没有开设的新版"高级编程"里?

"高级编程":Ruby/Rails高级编程 面向对象设计 性能优化,企业级应用等.
本帖最近评分记录
  • drive2me R币 +3 好建议! 2007-11-16 15:34

TOP

收藏了,哈哈!谢谢2位高手!
Flying Piggy...! 
天地人合一!

TOP

谢谢楼主,提供了这么好的ruby
success = 9999999.times{ handle ruby }

TOP

文章不错。但是这最后的警告:
“对于有关联的Model请谨慎使用cached_model,建议不使用。”

一般还是有关联的model多啊。。。

I.forget('you'){|something| something.remember.deepen}

TOP

2008-11-22 18:48 Crawled by CCBot/1.0 (+http://www.commoncrawl.org/bot.html) @38.103.63.61