238

In Rails, you can find the number of records using both Model.size and Model.count. If you're dealing with more complex queries is there any advantage to using one method over the other? How are they different?

For instance, I have users with photos. If I want to show a table of users and how many photos they have, will running many instances of user.photos.size be faster or slower than user.photos.count?

Thanks!

strivedi183
  • 4,749
  • 2
  • 31
  • 38
Andrew
  • 42,517
  • 51
  • 181
  • 281

7 Answers7

404

You should read that, it's still valid.

You'll adapt the function you use depending on your needs.

Basically:

  • if you already load all entries, say User.all, then you should use length to avoid another db query

  • if you haven't anything loaded, use count to make a count query on your db

  • if you don't want to bother with these considerations, use size which will adapt

Jo Liss
  • 30,333
  • 19
  • 121
  • 170
apneadiving
  • 114,565
  • 26
  • 219
  • 213
  • 38
    If `size` adapts to the situation anyway, then what need is there for `length` and `count` at all? – sscirrus May 21 '11 at 17:32
  • 31
    @sscirus - So that `size` can make a call to them when you make the call to `size` (after it determines which one to call). – Batkins Dec 30 '11 at 20:34
  • 44
    Be careful with just defaulting to size, however. For example if you create a new record without going through the relation, i.e. `Comment.create(post_id: post.id)`, your `post.comments.size` will not be up to date, while `post.comments.count` will. So just be careful. – mrbrdo Mar 31 '13 at 19:52
  • 16
    Also, if you build several objects through a relation: `company.devices.build(:name => "device1"); company.devices.build(:name => "device2")`, then `company.devices.size` and `.length` will include the number of objects you've built but haven't saved, `.count` will report only the count from the database. – Shawn J. Goff Sep 06 '13 at 18:54
  • 2
    one thing to mention is that `count` will issue a db query every time. so avoid using it inside loops – fengd Sep 23 '13 at 09:36
  • 6
    @sscirrus, size is a dangerous command since it's automated, sometimes you do want to query the db again. – Alex C Mar 17 '15 at 13:56
  • 2
    This answer may be missing some important information from the latest Rails documentation (currently Rails 5.2). The [#length](http://api.rubyonrails.org/classes/ActiveRecord/Associations/CollectionProxy.html#method-i-length) method will perform a `SELECT * ...` query, where the [#size](http://api.rubyonrails.org/classes/ActiveRecord/Associations/CollectionProxy.html#method-i-size) method will perform a `SELECT COUNT(*) ... ` query. Therefore `#size` is no longer able to be used "when you dont want to bother with these considerations" as it has a different use case than `#length`. – Todd Jun 28 '18 at 21:27
  • @Batkins - I know it's a little bit late :) but I have a Q, how `size` detects it needs to call `count`? In other words, is there a case other than `ModelName.all.size`? – Ahmed Salah Sep 03 '22 at 19:14
100

As the other answers state:

  • count will perform an SQL COUNT query
  • length will calculate the length of the resulting array
  • size will try to pick the most appropriate of the two to avoid excessive queries

But there is one more thing. We noticed a case where size acts differently to count/lengthaltogether, and I thought I'd share it since it is rare enough to be overlooked.

  • If you use a :counter_cache on a has_many association, size will use the cached count directly, and not make an extra query at all.

    class Image < ActiveRecord::Base
      belongs_to :product, counter_cache: true
    end
    
    class Product < ActiveRecord::Base
      has_many :images
    end
    
    > product = Product.first  # query, load product into memory
    > product.images.size      # no query, reads the :images_count column
    > product.images.count     # query, SQL COUNT
    > product.images.length    # query, loads images into memory
    

This behaviour is documented in the Rails Guides, but I either missed it the first time or forgot about it.

lime
  • 6,901
  • 4
  • 39
  • 50
  • In fact, prior to rails 5.0.0.beta1, this behavior would be triggered even if there is a `_count` column (without the `counter_cache: true` directive on the association). This has been fixed in https://github.com/rails/rails/commit/e0cb21f5f7 – cbliard May 29 '18 at 12:17
17

tl;dr

  • If you know you won't be needing the data use count.
  • If you know you will use or have used the data use length.
  • If you don't know where it is used or the speed difference is neglectable, use size...

count

Resolves to sending a Select count(*)... query to the DB. The way to go if you don't need the data, but just the count.

Example: count of new messages, total elements when only a page is going to be displayed, etc.

length

Loads the required data, i.e. the query as required, and then just counts it. The way to go if you are using the data.

Example: Summary of a fully loaded table, titles of displayed data, etc.

size

It checks if the data was loaded (i.e. already in rails) if so, then just count it, otherwise it calls count. (plus the pitfalls, already mentioned in other entries).

def size
  loaded? ? @records.length : count(:all)
end

What's the problem?

That you might be hitting the DB twice if you don't do it in the right order (e.g. if you render the number of elements in a table on top of the rendered table, there will be effectively 2 calls sent to the DB).

estani
  • 24,254
  • 2
  • 93
  • 76
8

Sometimes size "picks the wrong one" and returns a hash (which is what count would do)

In that case, use length to get an integer instead of hash.

jvalanen
  • 2,809
  • 1
  • 16
  • 9
  • I used '.size' on a Collection from a has_many instance and even though there was one record in the collection, size was returning a '0'. Using .count returned the correct value of '1'. – admazzola Dec 30 '17 at 21:23
3

The following strategies all make a call to the database to perform a COUNT(*) query.

Model.count

Model.all.size

records = Model.all
records.count

The following is not as efficient as it will load all records from the database into Ruby, which then counts the size of the collection.

records = Model.all
records.size

If your models have associations and you want to find the number of belonging objects (e.g. @customer.orders.size), you can avoid database queries (disk reads). Use a counter cache and Rails will keep the cache value up to date, and return that value in response to the size method.

Dennis
  • 56,821
  • 26
  • 143
  • 139
  • 4
    Both `Model.all.size` and `Model.all.count` generate a `count` query in Rails 4 and above. The real advantage of `size` is that it doesn't generate the count query if the association is already loaded. In Rails 3 and below, I believe `Model.all` is not a relation, hence all the records are already loaded. This answer might be out of date and I suggest deleting it. – Damon Aw Mar 31 '17 at 16:37
2

I recommended using the size function.

class Customer < ActiveRecord::Base
  has_many :customer_activities
end

class CustomerActivity < ActiveRecord::Base
  belongs_to :customer, counter_cache: true
end

Consider these two models. The customer has many customer activities.

If you use a :counter_cache on a has_many association, size will use the cached count directly, and not make an extra query at all.

Consider one example: in my database, one customer has 20,000 customer activities and I try to count the number of records of customer activities of that customer with each of count, length and size method. here below the benchmark report of all these methods.

            user     system      total        real
Count:     0.000000   0.000000   0.000000 (  0.006105)
Size:      0.010000   0.000000   0.010000 (  0.003797)
Length:    0.030000   0.000000   0.030000 (  0.026481)

so I found that using :counter_cache Size is the best option to calculate the number of records.

2

Here's a flowchart to simplify your decision-making process. Hope it helps.

Source: Difference Between the Length, Size, and Count Methods in Rails

length, size, and count methods in Rails

software_writer
  • 3,941
  • 9
  • 38
  • 64