単体テストのコードを見ていて、対象のテーブルに存在するレコード数を取得する際の記述が統一されていないことを発見しました。ある箇所では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
を使っておけば間違いなさそうでした。
おまけ
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