Rails counter_cache Model.count,没有任何关联,以使 SELECT COUNT (*) 更



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

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

比制作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钩中,并通过调用 Rails.cache.read 来覆盖Model.size

每当 Rails 首次初始化时,您可以通过在包含以下内容的配置/初始值设定项中放置一个名为 initialize_cache.rb 的文件来初始化缓存:

Rails.cache.write('elephant_count', 0) if Rails.cache.read('elephant_count').nil?

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

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

称重性能

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

如果计数器不需要始终保持 100% 准确,则可以改为使用 cron 作业或后台辅助角色定期更新缓存。

总结:

  1. 仅当需要这些计数器足以抵消创建/销毁记录所花费的稍长时间时,才应使用counter_cache。
  2. 我所知,使用 counter_cache 与使用回调的手动替代方案不太可能对性能造成太大损害。
  3. 如果缓存不需要准确,请利用这一点并减少执行计算的频率。

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

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

我个人使用memcache作为这样的事情的商店。只需确保根据需要使缓存保持最新即可。

如何定义这样的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

相关内容

  • 没有找到相关文章