要旨
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 されている