Rails 3.2 - 查询性能(Postgres)

时间:2012-03-28 22:45:47

标签: ruby-on-rails performance postgresql optimization

背景

我正在创建一个仪表板作为项目,我有一个查询,我认为这将是一个重大的性能问题:

<% for outlet in @outlets %>
    <% if Monitoring.where(:outlet_id => outlet.id).where('date(created_at) = ?', Date.today).exists? %>
        <li>
            <a class="done" href="<%= outlet_url(outlet) %>" rel="tooltip" title="<%= outlet.name %>"></a>
        </li>
    <% else %>
        <li>
            <a href="<%= outlet_url(outlet) %>" rel="tooltip" title="<%= outlet.name %>"></a>
        </li>
    <% end %>
<% end %>

我想要实现的是页面上的一系列点。如果锚标记有一个已完成的类,它将显示为绿色,如果不是,它将显示为红色(通过CSS完成)。

除了这里明显的DRY问题之外,这个查询非常繁重,所以我正在研究改进它的方法。

每天至少监控一次插座( An Outlet has_many:监控)。对于每个插座,我需要检查是否在特定日期对其进行了监控,并相应地输出HTML。

如果有人能帮助我,那就太棒了。 (此外,任何有关缓存此建议的建议都将受到赞赏。)

提前干杯:)。

3 个答案:

答案 0 :(得分:1)

您可以为当前监视器创建条件关联,然后使用includes来获取原始查询的关联当前监视。

class Outlet
  has many :current_monitorings, :class_name => "Monitoring",
    :conditions => proc { [ 'monitorings.created_at > ?', Time.now.midnight ] }
end

@outlets = Outlet.includes(:current_monitorings)

@outlets.each do |outlet|
  if outlet.current_monitorings.empty?
    # the no monitor today case
  else
    # it's been monitored today
  end
end

在Postgres级别,您可能会受益于监控的索引(outlet_id,created_at),以支持#includes隐含的外部联接。

顺便说一下,在视图中执行数据库查询是不好的方式。将域逻辑放在模型中,让控制器执行查询并将结果提供给表示层。

答案 1 :(得分:0)

也许试试:

<% @outlets.includes(:monitorings).each do |outlet| %>
  <% css_class = outlet.monitorings.any? { |m| m.created_at == Date.today } ? 'done' : '' %>
  <li><%= link_to '', outlet_url(outlet), :class => css_class, :rel => "tooltip", :title => outlet.name %></li>
<% end %>

它将执行1个大查询。

答案 2 :(得分:0)

缓存此方法的一个好方法是使用回调对数据库进行非规范化。在Outlet模型中,您可以添加一个名为last_monitored_on的字段;在保存监视器的任何时候,使用日期更新相应的Outlet模型。然后,您根本不必查询监视器。

您还可以考虑缓存该网页片段,并让它每天过期。