要旨
ActiveRecord::Relation#count
を使っておくのが良い。
size
や length
もあるが、キャッシュが効いて期待する値を返さない場合があるので、よほどそのような状況ではない限り、使用を避けるのが無難であろう。
やってはいけないのは、ActiveRecord::Relation#to_a
まず、一番やってはいけないのは ActiveRecord::Relation#to_a
して、その Array
に対して Array#size
or Array#length
することである。
これをするとwhere
で絞り込んだ全件が一度取得された後にメモリに格納されるので、遅いしDBもアプリケーションも無駄にリソースを消費する。対象件数が少なければ良いが、例えば数万件とかの規模になってしまうと、カラムの量と割り当てメモリにもよるが、コンテナで実行していればKubernetes等のオーケストレーションツールにOOM Killされてしまうこともある。
おすすめは、 ActiveRecord::Relation#count
おすすめは、 ActiveRecord::Relation#count
である。この理由は2点ある。
1つ目として、SQL の COUNT
を使用してくれる点である。まずSQLサーバの中でクエリが評価される際、不要なカラムの情報を取得しない分ディスクIOも早いうえ、インデックスを使用してくれるため、全件走査と比べ処理が早い事を期待できる。
2つ目として、SQLサーバからレスポンスが返るタイミングで該当件数の数値しか返らないことである。アプリケーションサーバの使用するリソースを ActiveRecord::Relation#to_a
と比べ大幅に節約することが可能である。
他にもsize
length
もあるが、使用には注意が必要
ActiveRecord::Relation#size
ActiveRecord::Relation#length
もあるが、クエリ内容によってはキャッシュが効くため注意が必要。
具体的には、キャッシュの使用有無が参考にした文献で紹介されているものの、根拠となっている実装は、現在の最新 main
ブランチだと削除されているメソッドのため、真偽不明で調査検証の必要がある。
結局どうすれば良いか
count
を使っておけば、キャッシュ無しで取得できることが保証されているようである。なので、ActiveRecordのパフォーマンスをよほどシビアに要求されるような箇所でなければ、 count
を使用するのが安全ではないか、という結論にしたい。
実装
ActiveRecord::Relation#size
ActiveRecord::Caluculations#count
ActiveRecord::Relation
に include
されている