急切加载生成较慢的查询

时间:2011-03-22 02:23:06

标签: ruby-on-rails activerecord eager-loading will-paginate

我正在优化我的应用并注意到一些有趣的东西。我最初在我的控制器中有这个陈述

@votes = Vote.paginate(:page => params[:page], :order=>"created_at DESC")

这在我看来

<% @votes.each do |vote| %>
<tr>
  <td><%= vote.user.display_name %></td>
...

我尝试更改控制器以使用预先加载:

@votes = Vote.includes(:user).paginate(:page => params[:page],
  :order=>"created_at DESC")

这样做,我注意到我的ActiveRecord查询时间加载投票/索引从180毫秒加倍到440毫秒。通过急切加载成功减少了查询数量。但是,我在急切的负载情况

中发现了这个耗时的查询
  SQL (306.5ms)  SELECT COUNT(DISTINCT "votes"."id") FROM "votes" LEFT OUTER JOIN "users" ON "users"."id" = "votes"."user_id"

为什么我的代码要求对左外连接进行计数?它不存在于非急切负载的情况下。在非急切负载的情况下,这是我能找到的最接近的陈述:

  SQL (30.5ms)  SELECT COUNT(*) FROM "votes"

这是与paginate有关吗?这是两者的某种组合吗?

1 个答案:

答案 0 :(得分:2)

是的,该查询似乎是由分页插件生成的。此查询是估计总页数所必需的。

但是如果你知道记录的数量(通过之前做一个简单的SELECT COUNT(*) FROM "votes"),你可以使用:total_entries选项将该数字传递给will_paginate!

(有关详细信息,请参阅WillPaginate::Finder::ClassMethods。)

顺便问一下,您是否为votes.user_id创建了一个索引?可能会减慢查询速度。我想知道为什么DISTINCT子句应该花费这么多时间,因为id可能已经有一个唯一约束(如果没有,请尝试添加一个)。