ActiveRecord: size vs count
Solution 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 uselength
to avoid another db queryif you haven't anything loaded, use
count
to make a count query on your dbif you don't want to bother with these considerations, use
size
which will adapt
Solution 2
As the other answers state:
-
count
will perform an SQLCOUNT
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
/length
altogether, and I thought I'd share it since it is rare enough to be overlooked.
-
If you use a
:counter_cache
on ahas_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.
Solution 3
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).
Solution 4
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.
Solution 5
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.
Related videos on Youtube
Comments
-
Andrew over 2 years
In Rails, you can find the number of records using both
Model.size
andModel.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 thanuser.photos.count
?Thanks!
-
sscirrus almost 13 yearsIf
size
adapts to the situation anyway, then what need is there forlength
andcount
at all? -
Batkins over 12 years@sscirus - So that
size
can make a call to them when you make the call tosize
(after it determines which one to call). -
mrbrdo about 11 yearsBe 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)
, yourpost.comments.size
will not be up to date, whilepost.comments.count
will. So just be careful. -
Shawn J. Goff over 10 yearsAlso, if you build several objects through a relation:
company.devices.build(:name => "device1"); company.devices.build(:name => "device2")
, thencompany.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. -
fengd over 10 yearsone thing to mention is that
count
will issue a db query every time. so avoid using it inside loops -
Alex C about 9 years@sscirrus, size is a dangerous command since it's automated, sometimes you do want to query the db again.
-
Damon Aw about 7 yearsBoth
Model.all.size
andModel.all.count
generate acount
query in Rails 4 and above. The real advantage ofsize
is that it doesn't generate the count query if the association is already loaded. In Rails 3 and below, I believeModel.all
is not a relation, hence all the records are already loaded. This answer might be out of date and I suggest deleting it. -
admazzola over 6 yearsI 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'.
-
cbliard almost 6 yearsIn fact, prior to rails 5.0.0.beta1, this behavior would be triggered even if there is a
_count
column (without thecounter_cache: true
directive on the association). This has been fixed in github.com/rails/rails/commit/e0cb21f5f7 -
Todd almost 6 yearsThis answer may be missing some important information from the latest Rails documentation (currently Rails 5.2). The #length method will perform a
SELECT * ...
query, where the #size method will perform aSELECT 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
. -
A moskal escaping from Russia over 2 years"If you don't know what you are doing"?
-
estani over 2 years@SebastianPalma too harsh? ok, rephrase it to be more exact (and polite :)