微炭酸ログ

Ruby や Rails を中心に。

【Rails】length, size, count, empty?, exists? などの使い分け

length()

https://api.rubyonrails.org/v6.1.3.2/classes/ActiveRecord/Associations/CollectionProxy.html#method-i-length

コレクションがすでにロードされている場合、length と size は同等です。そうでない場合で、とにかくレコードが必要になる場合、このメソッドは1つ少ないクエリを実行します。それ以外の場合は、size の方が効率的です。

  • Load されてない場合:SELECT して、その結果の長さを返す(SELECT COUNT じゃない)。Load もする。
  • Load されている場合:キャッシュを使う。

size()

https://api.rubyonrails.org/v6.1.3.2/classes/ActiveRecord/Associations/CollectionProxy.html#method-i-size

コレクションがロードされていない場合は、SELECT COUNT(*)クエリを実行します。それ以外の場合は、collection.size を呼び出します。コレクションがすでにロードされている場合、length と size は同等です。そうでない場合で、とにかくレコードが必要になる場合は、length のほうがクエリが1つ少なくなります。それ以外の場合は、size の方が効率的です。

  • Load されてない場合:SELECT COUNT を発行する。Load しない。
  • Load されている場合:キャッシュを使う。

count()

https://api.rubyonrails.org/v6.1.3.2/classes/ActiveRecord/Associations/CollectionProxy.html#method-i-count

  • Load されているかどうかに関わらず、毎回 SELECT COUNT を発行する。

empty?()

https://api.rubyonrails.org/v6.1.3.2/classes/ActiveRecord/Associations/CollectionProxy.html#method-i-empty-3F

コレクションがロードされている場合は、collection.size.zero?と同等です。コレクションがロードされていない場合は、!collection.exists? と同等です。コレクションがまだロードされておらず、とにかくレコードをフェッチする場合は、collection.length.zero? をお勧めします。

  • Load されてない場合:SQL を発行する。Load しない。
  • Load されている場合:キャッシュを使う。

exists?()

https://api.rubyonrails.org/classes/ActiveRecord/FinderMethods.html#method-i-exists-3F

  • Load されているかどうかに関わらず、毎回 SQLを発行する。

present?()

https://api.rubyonrails.org/classes/Object.html#method-i-present-3F

  • コレクションに対して呼んでいるだけなので、Load されていなければコレクションの呼び出しによって Load されるし、Load されていればコレクションの呼び出しにはキャッシュが使われるだけ。

blank?()

https://api.rubyonrails.org/classes/Object.html#method-i-blank-3F

  • present? の逆。

まとめ

以下の考え方でいくのがよさそう。

  • Load が済んでいるとき:length
  • サイズほしいけど Load も一緒にしたいとき:length
  • Load しなくていいからシンプルにサイズだけ欲しいとき:size または empty? または exists?
  • 常に最新の値が欲しいとき:count
  • コレクションに対しては present? や blank? は使わずに、length または size を使う。