是否可以在Rails中缓存自定义sql查询?



在我的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 %>

刷新浏览器三次显示查询运行了三次,查询的最后一次运行实际上比第一次长0.7 ms,所以我假设缓存不起作用或者我没有正确地做:)。你能告诉我我哪里做错了吗?

从任何标准来看,我都不是一个专家,我不明白如何使用<% cache从视图中触发缓存…do %>语法,因为在视图加载的时候还没有控制器查询已经运行,因此告诉Rails使用缓存副本已经太晚了?

from server logs…

首先

 (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 

3

  (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)

在控制器中缓存查询结果。您可以在一次调用中读或写回缓存(即,如果缓存中的数据不存在,则设置缓存中的数据)

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",如果数据存在,将从缓存中返回它。如果它不存在,块将被执行,它将被设置在缓存

从ActiveRecord缓存的角度来看:

我理解这一点的方式是ActiveRecord查询缓存是每个web请求。这意味着如果您在同一个请求中运行SQL查询两次,它将使用缓存,但在每个请求结束时清除缓存。

来源:ActiveRecord::QueryCache中间件来源

(我相信' ActiveRecord::Base。一般来说,执行调用被缓存,就像您使用ActiveRecord查询API进行的查询一样)

如果你只想在你的应用程序的生命周期中做一次查询(或者每几个小时一次),你可以使用另一个Rails API:缓存API将你的缓存存储在文件系统,内存,memcache或自定义存储中。Rails缓存/缓存存储指南。

如果你决定使用Rails.cache, Heroku开发中心在缓存策略上有一些代码示例,向你展示了Rails.cache的API看起来像什么。它很容易使用。

为什么片段缓存不像你期望的那样工作

视图中的缓存调用意味着你正在定义一个片段缓存。(请参阅Rails缓存/片段缓存指南部分)。这将缓存视图的HTML输出,正如您在日志中看到的那样。

但是片段缓存只适用于HTML。当你执行查询并将结果分配给@studentscoring时,你是在视图执行之前在控制器中执行的(对吗?)

ActiveRecord查询通常是懒惰的-执行延迟,直到真正需要的数据,如迭代记录-所以你的技巧可能在使用ActiveRecord查询API时有效。然而,我猜ActiveRecord::Base.execute查询并不懒惰。我无法证明,但你可以做个实验。

所以你的片段缓存可能会被使用,但你已经为控制器中的查询付出了代价。

最新更新