Railsでは、Model.size
とModel.count
の両方を使用してレコードの数を見つけることができます。より複雑なクエリを処理している場合、あるメソッドを他のメソッドよりも使用することに利点はありますか?それらはどう違いますか?
たとえば、写真のあるユーザーがいます。ユーザーの表とユーザーが持っている写真の数を表示したい場合、user.photos.size
の多くのインスタンスを実行すると、user.photos.count
よりも速くなりますか、遅くなりますか?
ありがとう!
that と読む必要がありますが、それはまだ有効です。
必要に応じて、使用する機能を調整します。
基本的に:
User.all
などのすべてのエントリをすでにロードしている場合、length
を使用して別のdbクエリを回避する必要があります
何もロードしていない場合は、count
を使用してデータベースでカウントクエリを作成します。
これらの考慮事項に煩わされたくない場合は、size
を使用してください。
他の答えが示すように:
count
はSQL COUNT
クエリを実行しますlength
は、結果の配列の長さを計算しますsize
は、過剰なクエリを回避するために、2つのうち最も適切なものを選択しようとしますしかし、もう1つあります。 size
がcount
/length
とまったく異なる動作をするケースに気付きました。見落とされるほどまれなので、共有したいと思いました。
:counter_cache
アソシエーションでhas_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
この動作は the Rails Guides に記載されていますが、初めて見逃したか、忘れてしまいました。
時々size
"間違ったものを選んで" ハッシュを返します(これはcount
がすることです)
その場合、length
を使用してhashではなくintegerを取得します。
以下の戦略はすべて、COUNT(*)
クエリを実行するためにデータベースを呼び出します。
Model.count
Model.all.size
records = Model.all
records.count
以下は、データベースからすべてのレコードをRubyにロードしてからコレクションのサイズをカウントするので、効率的ではありません。
records = Model.all
records.size
モデルに関連付けがあり、所属するオブジェクトの数(@customer.orders.size
など)を検索する場合、データベースクエリ(ディスク読み取り)を回避できます。 counter cache を使用すると、Railsはキャッシュ値を最新の状態に保ち、size
メソッドへの応答としてその値を返します。
サイズ関数を使用することをお勧めします。
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を使用する場合、sizeはキャッシュされたカウントを直接使用し、余分なクエリは一切行いません。
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を使用するのが最適なオプションであることがわかりました。
count
を使用してください。length
を使用してください。size
...を使用してください.Select count(*)...
クエリをDBに送信することを解決します。データは必要なく、カウントだけが必要な場合の対処法。
例:新しいメッセージの数、ページのみが表示される場合の合計要素など。
必要なデータ、つまり必要に応じてクエリを読み込み、それをカウントします。データを使用している場合の方法。
例:完全にロードされたテーブルの概要、表示されたデータのタイトルなど。
データがロードされたかどうか(つまり、すでにRailsにあるかどうか)をチェックし、ロードされている場合はカウントします。そうでない場合はcountを呼び出します。 (さらに、他のエントリで既に述べた落とし穴)。
def size
loaded? ? @records.length : count(:all)
end
どうしたの?
正しい順序で実行しないとDBに2回ヒットする可能性があります(たとえば、レンダリングされたテーブルの上にあるテーブルの要素の数をレンダリングすると、DBに事実上2つの呼び出しが送信されます)。