ruby-on-rails - ActiveRecord`includes'不将数据缓存在生产环境中

标签 ruby-on-rails caching activerecord heroku

我在Heroku中使用Rails 4.2

我对ActiveRecord的includes函数的理解是,它会预先获取所有相关数据,因此以后调用该关系时,不必执行额外的查询。

我看到它获取相关数据,但是在生产环境中(在Heroku上),每次调用该关系时,我也看到它再次获取数据。为什么会这样,我该如何解决?

这仅发生在生产中,而不发生在开发中。

这是我正在观察的功能:

  def max_outcome_scores()
    scores = Hash.new(0)
    logger.info '*** Running max_outcome_score ***'
    language_progresses.with_updates.
        includes(:progress_marker).find_each do |progress|
      scores[progress.progress_marker.topic_id] += progress.progress_marker.weight  * ProgressMarker.spread_text.keys.max
    end
    logger.info '*** Finished max_outcome_score ***'
    return scores
  end


该功能可以正常工作,但是数据库查询过多。这是我在日志中看到的内容:

2016-07-13T06:55:30.304893+00:00 app[web.1]: *** Running max_outcome_score ***
2016-07-13T06:55:30.308102+00:00 app[web.1]:   LanguageProgress Load (2.4ms)  SELECT  "language_progresses".* FROM "language_progresses" INNER JOIN "progress_updates" ON "progress_updates"."language_progress_id" = "language_progresses"."id" WHERE "language_progresses"."state_language_id" = $1  ORDER BY "language_progresses"."id" ASC LIMIT 1000  [["state_language_id", 209]]
2016-07-13T06:55:30.308882+00:00 app[web.1]:   ↳ app/models/state_language.rb:104:in `max_outcome_scores'
2016-07-13T06:55:30.313090+00:00 app[web.1]:   CACHE (0.0ms)  SELECT "progress_markers".* FROM "progress_markers" WHERE "progress_markers"."id" IN (70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 130, 80, 81, 82, 98, 99, 100, 101, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113, 56, 57, 58, 59, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 83, 84, 85, 86, 87, 88, 90, 91, 92, 93, 94, 131, 89, 95, 96, 97, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129)
2016-07-13T06:55:30.314067+00:00 app[web.1]:   ↳ app/models/state_language.rb:104:in `max_outcome_scores'
2016-07-13T06:55:30.317657+00:00 app[web.1]:   CACHE (0.0ms)  SELECT  "progress_markers".* FROM "progress_markers" WHERE "progress_markers"."id" = $1 LIMIT 1  [["id", 71]]
2016-07-13T06:55:30.318379+00:00 app[web.1]:   ↳ app/models/state_language.rb:105:in `block in max_outcome_scores'
2016-07-13T06:55:30.318730+00:00 app[web.1]:   CACHE (0.0ms)  SELECT  "progress_markers".* FROM "progress_markers" WHERE "progress_markers"."id" = $1 LIMIT 1  [["id", 71]]
2016-07-13T06:55:30.319448+00:00 app[web.1]:   ↳ app/models/state_language.rb:105:in `block in max_outcome_scores'
2016-07-13T06:55:30.319872+00:00 app[web.1]:   CACHE (0.0ms)  SELECT  "progress_markers".* FROM "progress_markers" WHERE "progress_markers"."id" = $1 LIMIT 1  [["id", 75]]
2016-07-13T06:55:30.320580+00:00 app[web.1]:   ↳ app/models/state_language.rb:105:in `block in max_outcome_scores'
2016-07-13T06:55:30.320953+00:00 app[web.1]:   CACHE (0.0ms)  SELECT  "progress_markers".* FROM "progress_markers" WHERE "progress_markers"."id" = $1 LIMIT 1  [["id", 77]]
2016-07-13T06:55:30.321671+00:00 app[web.1]:   ↳ app/models/state_language.rb:105:in `block in max_outcome_scores'
2016-07-13T06:55:30.322226+00:00 app[web.1]:   CACHE (0.0ms)  SELECT  "progress_markers".* FROM "progress_markers" WHERE "progress_markers"."id" = $1 LIMIT 1  [["id", 103]]
2016-07-13T06:55:30.322938+00:00 app[web.1]:   ↳ app/models/state_language.rb:105:in `block in max_outcome_scores'
2016-07-13T06:55:30.323543+00:00 app[web.1]:   CACHE (0.0ms)  SELECT  "progress_markers".* FROM "progress_markers" WHERE "progress_markers"."id" = $1 LIMIT 1  [["id", 60]]
2016-07-13T06:55:30.324251+00:00 app[web.1]:   ↳ app/models/state_language.rb:105:in `block in max_outcome_scores'
2016-07-13T06:55:30.324966+00:00 app[web.1]: *** Finished max_outcome_score ***


我已将日志配置为在生成查询的代码中输出该行。第104行是带有includes的行,第105行是find-each块内部的行。

最佳答案

事实证明,即使ActiveRecord确实预先收集了所有必要的数据,当要求其提供否则需要去数据库获取的数据时,它仍然会建立相关的查询,而不是使用它,它只是从缓存中提取数据。然后,它记录它构建的查询,但未在数据库上使用。

在某些情况下,看到这些查询可能对测试和调试很有用,但是大多数时候我发现它们只是堵塞了日志。

Raphael提供了一种suppress this logging的方式。将此代码放在config/initializers中的ruby文件中

# Create logger that ignores messages containing “CACHE”
class CacheFreeLogger < ::Logger
  def debug(message, *args, &block)
    super unless message.include? 'CACHE'
  end
end

# Overwrite ActiveRecord’s logger
ActiveRecord::Base.logger = ActiveSupport::TaggedLogging.new(
  CacheFreeLogger.new(STDOUT)) unless Rails.env.test?

关于ruby-on-rails - ActiveRecord`includes'不将数据缓存在生产环境中,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38344808/

相关文章:

ruby-on-rails - Rails 中的推杆 : "Unknown auth_key" - server side not triggering events

ruby-on-rails - 如何在 Rails 中通过继承获得多态关系?

ruby-on-rails - ActiveRecord 在将 JSONB/Hash 与 Array 一起使用时构造不正确的 SQL

ruby-on-rails - Ruby on Rails 推送通知

ruby-on-rails - 如何将自定义路由添加到单例资源?

ruby-on-rails - 单表继承和 ActiveRecord 关联

caching - 在 getters/setters 中缓存?

android - 使用 Zumero 同步 android 应用程序,更改缓存文件的位置

java - 如何在服务器端创建java级缓存

ruby-on-rails - 按子属性值之和排序模型