复杂的ActiveRecord案例中大小,长度和计数之间的差异

时间:2012-08-10 16:04:55

标签: sql ruby-on-rails activerecord

[10] pry(main)> r.respondents.select(:name).uniq.size

(1.1ms)  SELECT DISTINCT COUNT("respondents"."name") FROM "respondents" 
INNER JOIN "values" ON "respondents"."id" = "values"."respondent_id" WHERE 
"values"."round_id" = 37 => 495

[11] pry(main)> r.respondents.select(:name).uniq.length

Respondent Load (1.1ms)  SELECT DISTINCT name FROM "respondents" 
INNER JOIN "values" ON "respondents"."id" = "values"."respondent_id" WHERE
"values"."round_id" = 37 => 6

为什么每个查询返回的区别?

3 个答案:

答案 0 :(得分:6)

.count #=> this always triggers a SELECT COUNT(*) on the database

.size #=> if the collection has been loaded, defers to Enumerable#size, else does the SELECT COUNT(*)

.length #=> always loads the collection and then defers to Enumerable#size

答案 1 :(得分:1)

r.respondents.select(:name).uniq返回一个ActiveRecord :: Relation对象,该对象将覆盖size

请参阅:http://api.rubyonrails.org/classes/ActiveRecord/Relation.html#method-i-size

在这样的对象上调用size检查对象是否“已加载”。

# Returns size of the records.
def size
  loaded? ? @records.length : count
end

如果是“已加载”,则返回@records数组的长度。否则,它会调用count,其中没有参数,将为“return a count of all the rows for the model.

那为什么会这样呢?如果首先调用to_aexplain,则只会“加载”AR :: Relation:

https://github.com/rails/rails/blob/master/activerecord/lib/active_record/relation.rb

为什么会在load方法上方的评论中解释:

# Causes the records to be loaded from the database if they have not
# been loaded already. You can use this if for some reason you need
# to explicitly load some records before actually using them. The
# return value is the relation itself, not the records.
#
#   Post.where(published: true).load # => #<ActiveRecord::Relation>
def load
  unless loaded?
    # We monitor here the entire execution rather than individual SELECTs
    # because from the point of view of the user fetching the records of a
    # relation is a single unit of work. You want to know if this call takes
    # too long, not if the individual queries take too long.
    #
    # It could be the case that none of the queries involved surpass the
    # threshold, and at the same time the sum of them all does. The user
    # should get a query plan logged in that case.
    logging_query_plan { exec_queries }
  end

  self
end

因此,使用AR::Relation#size可能是衡量此关系查询潜在复杂程度的大小,其中length会回退到返回记录的计数。

答案 2 :(得分:0)

将Rails 3.2转换为4.1时,AR :: Relation#size似乎不同。以前它返回了&#34;行的数量&#34;而(在我的情况下)它现在返回一个哈希。更改为使用#count似乎与3.2中的#size具有相同的结果。我在这里做了一点模糊,因为他们在&#39; rails console&#39;在通过&#;; rails server&#39;运行时,4.1上没有给出相同的结果在4.1