9

我正在汇总我的一个模型中的行数,Model.count并且有点担心性能,因为最终,这个模型会变得非常大,因此SELECT COUNT (*)非常慢。

counter_cache没有关系有没有办法使用:belongs_to?或者另一种计算行数的性能友好的方式?我想过制作另一个模型,只是一个我存储这样的计算但不确定这是最好的方法的模型。

4

4 回答 4

13

比制作​​模型更简单的Cache方法是使用Rails.cache.

Rails.cache.read("elephant_count") #=> nil
Rails.cache.write("elephant_count", 1) #=> true
Rails.cache.read("elephant_count") #=> 1

Rails 默认使用文件存储(tmp/cache)。

然后,您可以将 Rails.cache.write 增量和减量放入模型after_createafter_destroy挂钩中,并通过Model.size调用 Rails.cache.read 覆盖。

initialize_cache.rb您可以在 Rails 首次初始化时通过在 config/initializers 中放置一个类似以下内容的文件来初始化缓存:

Rails.cache.write('elephant_count', 0) if Rails.cache.read('elephant_count').nil?
于 2011-05-12T02:17:40.183 回答
11

如果您想要维护一个计数器,无论是使用counter_cache还是手动执行,Rails 都会使用回调来维护您的计数器,这将在创建/销毁新后代时增加/减少计数器。

我不知道在counter_cache不使用belongs_to关系的情况下存储 a 的方法,因为只有父级才能存储子级的计数。

称重性能

如果您的表将变得“大”,请使用大量行填充您的测试数据库,然后开始运行一些 SQL 查询EXPLAIN以获取数据库查询的性能。查看在创建/销毁记录时的性能影响counter_cache是否被您首先需要访问这些计数器的频率所抵消。

如果计数器不需要始终 100% 准确,您可以改为使用cron作业或后台工作程序定期更新缓存。

总之:

  1. 如果您需要这些计数器足以抵消创建/销毁记录所花费的稍长时间,则应仅使用 counter_cache。
  2. counter_cache据我所知,使用与使用回调的手动替代方案相比,不太可能对性能造成很大损害。
  3. 如果缓存不需要准确,请利用它并减少执行计算的频率。
于 2011-05-12T01:46:22.383 回答
6

查看http://guides.rubyonrails.org/caching_with_rails.html 具体来说,您需要查看有关缓存存储的部分。使用缓存存储,您可以将任意事物的值存储到缓存中。

例如,您可以在模型上调用一个名为 get_count 的方法,该方法最初由计数填充,但通过 after_create 回调递增 1。如果没有必要保持最新,您可以每 x 分钟更新一次,以便您最准确。

我个人使用 memcache 作为这样的存储。只要确保根据您的需要保持缓存是最新的。

于 2011-05-12T01:43:08.150 回答
0

如何定义这样的CachedCount关注点?

module CachedCount
  extend ActiveSupport::Concern

  included do
    after_create :increment_cached_count
    after_destroy :decrement_cached_count
  end

  class_methods do
    def count
      return cached_count if cached_count
      Rails.cache.write(cached_count_key, super)
      Rails.cache.read(cached_count_key) || super # fallback because in some Rails env. Rails.cache may not be available
    end

    def cached_count_key
      "#{model_name.collection}_count"
    end

    def cached_count
      Rails.cache.read(cached_count_key)
    end
  end

  def increment_cached_count
    return self.class.count unless self.class.cached_count
    Rails.cache.write(self.class.cached_count_key, self.class.cached_count + 1)
  end

  def decrement_cached_count
    return self.class.count unless self.class.cached_count
    Rails.cache.write(self.class.cached_count_key, self.class.cached_count - 1)
  end
end

然后将其包含在您的众多模型中:

class MyNumerousModel
include CachedCount

# [...]

end

现在,每次调用MyNumerousModel.count时,实际上都是在调用关注点中的类方法。当您创建或销毁 MyNumerousModel 的一个实例时,after_createafter_destroy回调负责更新MyNumerousModel.cached_count.

于 2021-01-15T09:06:39.963 回答