【问题标题】:How to enable caching of model data?如何启用模型数据的缓存?
【发布时间】:2017-02-22 18:37:39
【问题描述】:

如何跨请求/操作启用缓存?

我的堆栈:

  • Rails 4.2.7
  • Postgres 9.5

我在 Rails 日志中注意到以下内容

  Country Load (0.4ms)  SELECT  "countries".* FROM "countries" WHERE "countries"."iso" = $1 LIMIT 1  [["iso", "US"]]
  State Load (1.4ms)  SELECT  "states".* FROM "states" WHERE "states"."iso" = $1 AND "states"."country_id" = $2 LIMIT 1  [["iso", "OH"], ["country_id", 233]]
  Country Load (0.3ms)  SELECT  "countries".* FROM "countries" WHERE "countries"."iso" = $1 LIMIT 1  [["iso", "US"]]
  State Load (1.1ms)  SELECT  "states".* FROM "states" WHERE "states"."iso" = $1 AND "states"."country_id" = $2 LIMIT 1  [["iso", "OH"], ["country_id", 233]]
  Country Load (3.6ms)  SELECT  "countries".* FROM "countries" WHERE "countries"."iso" = $1 LIMIT 1  [["iso", "US"]]
  State Load (1.2ms)  SELECT  "states".* FROM "states" WHERE "states"."iso" = $1 AND "states"."country_id" = $2 LIMIT 1  [["iso", "OH"], ["country_id", 233]]

请注意,相同的查询正在快速连续地对我的数据库运行多次。有什么方法可以向 Rails 表明某些表/模型不太可能更改,因此某些查找可以缓存在应用服务器上?

【问题讨论】:

    标签: ruby-on-rails postgresql ruby-on-rails-4 caching model


    【解决方案1】:

    有什么方法可以让 Rails 知道某些表/模型 不太可能更改,因此可以缓存某些查找 应用服务器?

    当然,模型缓存似乎非常适合这里。

    Here's the article 可以让您很好地了解如何设置不同类型的缓存。

    另外,请查看 official guides 缓存。

    基本上,您想研究模型缓存。

    您可以编写扩展并在要缓存的模型中使用它:

    module ModelCachingExtention
      extend ActiveSupport::Concern
    
      included do
        class << self
          # The first time you call Model.all_cached it will cache the collection,
          # each consequent call will not fire the DB query
          def all_cached
            Rails.cache.fetch(['cached_', name.underscore.to_s, 's']) { all.load }
          end
        end
    
        after_commit :clear_cache
    
        private
    
        # Making sure, that data is in consistent state by removing the cache
        # everytime, the table is touched (eg some record is edited/created/destroyed etc).
        def clear_cache
          Rails.cache.delete(['cached_', self.class.name.underscore.to_s, 's'])
        end
      end
    end
    

    然后在模型中使用:

    class Country < ActiveRecord::Base
      include ModelCachingExtention
    end
    

    现在,当使用 Country.all_cached 时,您将返回缓存的集合,其中包含零个数据库查询(一旦被缓存)。

    【讨论】:

    • 所以我理解正确,缓存查询的唯一方法是编写一个新方法(例如“find_by_id_cached”),然后在我的应用程序中更改我的调用以使用新查询。你说的是这个吗?
    • @Dave 正如我所说,做事的方法总是很少。这是最小化数据库查询的方法之一。您可以查看我提供的链接 + this nice railscast。但是使用所描述的方法 - 实际上,您必须跨应用程序更改您的调用。默认情况下,Rails 已经完成了一些缓存。
    • 您发布的链接——sitepoint.com 网站,不处理查询缓存,除了您在答案中给出的一个例外(它更多地谈论页面缓存)。我会看看你的 Railscast。
    • @Dave 毕竟,这都是数据缓存,是的,链接更多的是关于缓存类型,可能我在提供它时使用的措辞不准确。至于 railscast - 我希望它是我的 :)
    【解决方案2】:

    在单个请求中,Rails 已经缓存了查询。您将在日志文件中看到它,前缀为 CACHE。某些操作,例如在您的请求中插入新记录会导致 clear_query_cache 并且所有缓存条目都消失了。

    如果您希望查询缓存的使用寿命更长,则必须自己完成。您可以为此使用 Rails 缓存功能:

    Rails.cache.fetch("countries iso: #{iso}", expires_in: 1.hour) do
      Country.where(iso: iso).all
    end
    

    您也可以使用内存缓存。使用 memcache,您可以在多个服务器之间共享缓存数据。 您必须在您的特定环境配置中进行设置。

    config.cache_store = :mem_cache_store, "cache-1.example.com", "cache-2.example.com"

    【讨论】:

    • 我在日志文件中的任何地方都看不到包含单词“CACHE”的行。我在我的 Mac El Capitan 机器上以开发模式运行,所以也许我需要启用 anotehr 设置,但我认为没有使用缓存,否则为什么会对数据库执行查询。
    • 此缓存仅在启用的控制器操作内。尝试在一个操作中多次调用Country.all; Country.all,然后您应该首先看到Country Load,然后再看到CACHE。如果没有,请检查 config.cache_store 的设置。
    • 我已经更新了我的问题,以反映我对缓存超出单个操作感兴趣。我的问题是指在应用程序生命周期内更广泛地缓存只读数据。
    • 然后看看@Andrey Deineko 的遮阳篷和Rails 缓存指南。 @data = Rails.cache.fetch("your perfect cache key", expires_in: 1.hour) { fetch_what_ever_you_want() } 是关键。在开发模式下,您必须启用这种缓存。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-04-12
    • 1970-01-01
    • 1970-01-01
    • 2011-01-18
    • 2021-01-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多