ActiveRecord: size vs count

2019-01-02 16:28发布

问题:

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!

回答1:

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



回答2:

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.



回答3:

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.



回答4:

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.



标签: