3
[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

各クエリが返すものに違いがあるのはなぜですか?

4

3 に答える 3

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
于 2012-08-10T19:16:30.130 に答える
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。これは、引数なしで、 「モデルのすべての行の数を返します」 。

では、なぜこのような振る舞いをするのでしょうか? to_aAR::Relation は、またはexplainが最初に呼び出された場合にのみ「ロード」されます。

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、返されたレコードの数にフォールバックします。

于 2012-08-10T18:34:59.317 に答える