在我的Rails 4应用程序的home_controller中,我执行自定义SQL查询并将结果保存到实例变量
@studentscoring = ActiveRecord::Base.connection.execute sql_string_student
然后,我在配置开发config.action_controller.perform_caching = true
中将缓存设置为true并重新启动应用程序后,在视图中的相关变量周围设置缓存。
<% cache @studentscoring do%>
<% for lawyer in @studentscoring %>
<div class="span2">
<div class="row">
<%= tiny_gravatar_for lawyer['name'], lawyer['email'] %>
</div>
...... #code ommitted
</div>
<% end %>
<% end %>
刷新浏览器三次显示查询分别运行三次,查询的最后一次运行实际上比第一次运行时长.7ms,所以我假设缓存不起作用或者我没有正确执行:)。你能告诉我我做错了什么吗?
不是任何标准的专家,我不明白如何使用&lt;%cache ... do%&gt;从视图中触发缓存。语法,因为在加载视图时尚未运行控制器查询,因此告诉Rails使用缓存副本为时已晚?
来自服务器日志...
第一
(1.1ms) with cte_scoring as (
select
users.id, users.name, users.email,
(select Coalesce(sum(value),0) from answer_votes where (answer_votes.user_id = users.id) AND (created_at >= Current_Date - interval '7 day')) +
(select Coalesce(sum(value),0) from best_answers where (best_answers.user_id = users.id) AND (created_at >= Current_Date - interval '7 day')) +
(select Coalesce(sum(value),0) from contributions where (contributions.user_id = users.id) AND (created_at >= Current_Date - interval '7 day')) total_score
from
users
where
users.student = 'true')
select id,
name,
email,
total_score
from cte_scoring
order by total_score desc
limit 5
第三
(1.8ms) with cte_scoring as (
select
users.id, users.name, users.email,
(select Coalesce(sum(value),0) from answer_votes where (answer_votes.user_id = users.id) AND (created_at >= Current_Date - interval '7 day')) +
(select Coalesce(sum(value),0) from best_answers where (best_answers.user_id = users.id) AND (created_at >= Current_Date - interval '7 day')) +
(select Coalesce(sum(value),0) from contributions where (contributions.user_id = users.id) AND (created_at >= Current_Date - interval '7 day')) total_score
from
users
where
users.student = 'true')
select id,
name,
email,
total_score
from cte_scoring
order by total_score desc
limit 5
更新
日志显示它正在读取一个片段(在运行上面的查询之后),那么为什么查询会有不同的时间而后面的查询会变慢?如果有一个要读取的片段,我会认为根本不会运行查询。
Read fragment views/id/75/name/Retarded Student/email/retarstudent@gmail.com/total_score/0/id/83/name/Jim Beam/email/jimbean@gmail.com/total_score/0/id/79/name/Weird Student/email/weirdstudent@gmail.com/total_score/0/id/80/name/VegetableSTudent/email/veggiestudent@gmail.com/total_score/0/c9638e467bfd0fbf5b619ab411182256 (0.3ms)
答案 0 :(得分:8)
从ActiveRecord缓存角度来看:
我理解这一点的方式是ActiveRecord查询缓存是每个Web请求。这意味着如果您在使用缓存的同一请求中运行两次SQL查询,但在每个请求结束时清除缓存。
来源:ActiveRecord::QueryCache middleware source
(我相信`ActiveRecord :: Base.execute调用通常会被缓存,就像你使用ActiveRecord查询API进行的查询一样)
如果您只想为应用程序的生命周期执行一次查询(或每隔几个小时执行一次),您可以使用另一个Rails API:缓存API,用于将缓存存储在文件系统,内存,内存缓存中,或者在自定义商店中。 The Rails Guide on Caching / Cache Stores。
如果您决定使用Rails.cache
,Heroku Dev Center on Caching Strategies会有一些代码示例显示Rails.cache
的API是什么样的。这很容易使用。
为什么片段缓存无法像您期望的那样工作
视图中的缓存调用意味着您正在定义片段缓存。 (见Rails Guide on Caching / Fragment caching section)。这将缓存视图的HTML输出,正如您在日志中看到的那样。
但片段缓存仅适用于HTML。当您执行查询并将结果分配给@studentscoring
时,您在控制器中执行此操作(对吗?)。
ActiveRecord查询通常是懒惰的 - 执行被延迟直到真正需要数据,比如迭代记录 - 所以你的技巧可能在使用ActiveRecord查询API时起作用。但是,我猜测ActiveRecord::Base.execute
查询不是懒惰的。我无法证明这一点,但你可以进行实验。
因此可以使用您的片段缓存,但您已经为控制器中的查询付出了代价。
答案 1 :(得分:7)
将查询结果缓存在控制器中。您可以在一次调用中读取或写回缓存(即,如果数据尚不存在,则将数据设置在缓存中)
def index
@studentscoring = Rails.cache.fetch("your_cache_key", :expires_in => 5.minutes) do
ActiveRecord::Base.connection.select_rows(sql_string_student)
end
end
因此,上面将首先检查"your_cache_key"
的缓存,如果数据存在则将从缓存中返回。如果它不存在,则块将执行,它将在缓存中设置