ActiveRecord:サイズとカウント


201

Railsでは、Model.sizeおよびの両方を使用してレコード数を見つけることができますModel.count。より複雑なクエリを処理している場合、1つの方法を他の方法よりも使用することの利点はありますか?それらはどう違いますか?

たとえば、写真のあるユーザーがいます。ユーザーとユーザーが保持している写真の数の表を表示したい場合、多くのインスタンスを実行するのはuser.photos.sizeより高速か低速user.photos.countか?

ありがとう!

回答:


344

あなたはそれを読むべきです、それはまだ有効です。

必要に応じて、使用する機能を調整します。

基本的に:

  • すでにすべてのエントリをロードしている場合、たとえばUser.all、次のlengthdbクエリを回避するために使用する必要があります

  • 何もロードしていない場合countは、dbでカウントクエリを作成するために使用します

  • これらの考慮事項に煩わされたくない場合sizeは、適応する使用


35
場合はsize、とにかく状況に適応し、その後、どのような必要性のためにそこにあるlengthcountまったく?
sscirrus

27
@sscirus-これsizeにより、size(どちらを呼び出すかを決定した後で)を呼び出すときに、それらを呼び出すことができます。
Batkins 2011

35
ただし、デフォルトのサイズに注意してください。たとえば、リレーションを経由せずに新しいレコードを作成した場合、つまりComment.create(post_id: post.id)post.comments.size最新の状態にpost.comments.countはなりませんが、最新の状態になります。だから注意してください。
mrbrdo 2013年

14
また、あなたは関係を通じて複数のオブジェクトを構築する場合:company.devices.build(:name => "device1"); company.devices.build(:name => "device2")それから、company.devices.size.lengthあなたが建てられましたが、保存していないオブジェクトの数が含まれますが、.countデータベースからのみのカウントを報告します。
Shawn J. Goff 2013

6
@sscirrus、自動化されているため、sizeは危険なコマンドです。場合によっては、dbを再度クエリする必要があります。
Alex C

79

他の答えが述べるように:

  • countSQL COUNTクエリを実行します
  • length 結果の配列の長さを計算します
  • size 過剰なクエリを回避するために、2つのうち最も適切なものを選択しようとします

しかし、もう1つあります。全体的sizecount/ と違う振る舞いをするケースに気づき、length見過ごすほど珍しいので共有したいと思いました。

  • あなたが使用している場合:counter_cachehas_many協会、size直接カウントキャッシュされて使用し、すべての余分なクエリをすることはありません。

    class Image < ActiveRecord::Base
      belongs_to :product, counter_cache: true
    end
    
    class Product < ActiveRecord::Base
      has_many :images
    end
    
    > product = Product.first  # query, load product into memory
    > product.images.size      # no query, reads the :images_count column
    > product.images.count     # query, SQL COUNT
    > product.images.length    # query, loads images into memory

この動作はRailsガイドに記載されていますが、初めて見逃したか、忘れていました。


実際、rails 5.0.0.beta1より前のバージョンでは、_countcounter_cache: true関連付けのディレクティブなしで)列があったとしても、この動作がトリガーされていました。これがで修正されていgithub.com/rails/rails/commit/e0cb21f5f7
cbliard

8

時々size「間違ったものを選択」し、ハッシュ(これは何をcountするか)

その場合は、ハッシュではなく整数lengthを取得するために使用します。


has_manyインスタンスのコレクションで「.size」を使用しました。コレクションに1つのレコードがあったとしても、サイズは「0」を返していました。.countを使用すると、正しい値「1」が返されました。
admazzola 2017

4

tl; dr

  • データを使用する必要がないことがわかっている場合 count
  • データを使用する、または使用したことがわかっている場合 length
  • 何をしているのかわからない場合は、size...

カウント

送信に解決 Select count(*)...クエリをDBます。データが必要ない場合の方法ですが、カウントのみです。

例:新しいメッセージの数、ページのみが表示される場合の合計要素など。

長さ

必要なデータ、つまり必要に応じてクエリを読み込み、それをカウントします。データを使用している場合の方法。

例:完全に読み込まれたテーブルの概要、表示されたデータのタイトルなど

サイズ

データがロードされているかどうか(つまり、すでにレールにあるかどうか)をチェックし、ロードされている場合はそれをカウントし、そうでない場合はcountを呼び出します。(さらに、他のエントリですでに言及されている落とし穴)。

def size
  loaded? ? @records.length : count(:all)
end

どうしたの?

正しい順序で実行しないと、DBを2回ヒットする可能性があります(たとえば、レンダリングされたテーブルの上にあるテーブルの要素数をレンダリングすると、実質的に2つの呼び出しがDBに送信されます)。


3

次の戦略はすべて、データベースを呼び出してCOUNT(*)クエリを実行します。

Model.count

Model.all.size

records = Model.all
records.count

以下は、データベースからすべてのレコードをRubyにロードし、コレクションのサイズをカウントするため、効率的ではありません。

records = Model.all
records.size

モデルに関連付けがあり、所属するオブジェクトの数(など@customer.orders.size)を知りたい場合は、データベースクエリ(ディスク読み取り)を回避できます。カウンタキャッシュを使用すると、Railsはキャッシュ値を最新の状態に保ち、sizeメソッドに応答してその値を返します。


2
両方とも、Rails 4以上でクエリModel.all.sizeModel.all.count生成しcountます。の本当の利点はsize、関連付けが既に読み込まれている場合、カウントクエリが生成されないことです。Rails 3以前Model.allでは、リレーションではないので、すべてのレコードがすでに読み込まれています。この回答は古くなっている可能性があるため、削除することをお勧めします。
Damon Aw 2017年

1

サイズ関数の使用をお勧めします。

class Customer < ActiveRecord::Base
  has_many :customer_activities
end

class CustomerActivity < ActiveRecord::Base
  belongs_to :customer, counter_cache: true
end

これらの2つのモデルについて考えます。顧客には多くの顧客活動があります。

has_manyアソシエーションで:counter_cacheを使用する場合、サイズはキャッシュされたカウントを直接使用し、追加のクエリをまったく作成しません。

1つの例を考えてみます。私のデータベースでは、1人の顧客が20,000の顧客活動を持っているので、その顧客の顧客活動のレコード数を、カウント、長さ、サイズの各方法でカウントしようとしています。これらのメソッドすべてのベンチマークレポートを以下に示します。

            user     system      total        real
Count:     0.000000   0.000000   0.000000 (  0.006105)
Size:      0.010000   0.000000   0.010000 (  0.003797)
Length:    0.030000   0.000000   0.030000 (  0.026481)

そのため、:counter_cache Sizeを使用するのが、レコード数を計算するための最良のオプションであることがわかりました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.