やわらかテック

興味のあること。業務を通して得られた発見。個人的に試してみたことをアウトプットしています🍵

【ActiveRecord】レコード数を取得するにはlengthやcountではなくsizeを使っておけば良さそう

単体テストのコードを見ていて、対象のテーブルに存在するレコード数を取得する際の記述が統一されていないことを発見しました。ある箇所ではUser.all.sizeと記述されており、ある箇所ではUser.countと記述されており、どの方法で取得するのが効率が良いのか気になったので調べてみました。僕としてはSELECT COUNT(*) FROM usersというSQLが発行されてくれればOKです。

それぞれの書き方をした際に、どのようなSQLが発行されるかをテーブルにまとめてみました。

コード 発行されるSQL
User.all.size SELECT COUNT(*) FROM "users"
User.all.count SELECT COUNT(*) FROM "users"
User.all.length SELECT "users".* FROM "users"
User.count SELECT COUNT(*) FROM "users"
User.count('users.id') SELECT COUNT(users.id) FROM "users"

発行されるSQLを比べて見ると、ほとんどがSELECT COUNT(*) FROM "users"になっています。
lengthだけはSQLを発行して取得したレコード数の配列の要素数を確認するため、COUNT関数が呼び出されていません。SQLのパフォーマンスだけを考えればUser.count('users.id')と書くのが良いのでしょうが、わざわざ引数にidを指定するのは手間でActiveRecordっぽくないので、User.all.lengthでなければ、どれでも良さそうです。

ただ、こちらの記事でも触れられている通り、.sizeに関してはキャッシュが適応される場合があるとのことで、User.all.sizeを使っておけば間違いなさそうでした。

qiita.com

おまけ

User.countがいけるなら...と思って試してみたけどエラーになった書き方です。

[3] pry(main)> User.size
NoMethodError: undefined method `size' for User:Class
[21] pry(main)> User.length
NoMethodError: undefined method `length' for User:Class

参考文献