dogwood008の開発メモ!

最近のマイブームは機械学習, Ruby on Rails。中でも機械学習を使った金融商品の自動取引に興味があります。

【ActiveRecord/Rails】レコード数を数える時はcountを使うと確実、size, lengthとの違い

要旨

ActiveRecord::Relation#count を使っておくのが良い。

sizelength もあるが、キャッシュが効いて期待する値を返さない場合があるので、よほどそのような状況ではない限り、使用を避けるのが無難であろう。

やってはいけないのは、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

github.com

ActiveRecord::Caluculations#count

ActiveRecord::Relationinclude されている

github.com

ActiveRecord::ConnectionAdapters::StatementPool

github.com

ActiveRecord::Result#length

github.com

参考

bhserna.com

ohbarye.hatenablog.jp

qiita.com

www.lanches.co.jp