Difference between “count” and “length” in Rails.

I made an interesting discovery the other day between how “count” and “length” function with an ActiveRecord model, one that can be exploited effectively to speed up an app, as long as you understand the consequences.

  • Invoking “count” on an array (or dependent relationship) will always hit the database, and do something similar to select count(id) as count_all from contacts every time you invoke it.
  • Invoking “length” on an array (or dependent relationship) will only hit the database once. If the relationship has already been populated (say by :include-ing the dependent objects in your Model.find method), the database won’t get hit at all.

So – if you’re OK not getting a count that’s 100% accurate at the time of method invocation, “length” will do the right thing and run the necessary SQL statement the first time it’s run. Otherwise, it’ll give you the array count, which may be out of sync with the database.

This can have significant performance benefits if you’re iterating through many records and emitting counts of dependent objects. :include-ing the dependent objects and using “length” decreased the SQL expense of a page view 40 fold in one case.

Once again, it’s good to know your tools.

4 thoughts on “Difference between “count” and “length” in Rails.

  1. Pingback: Vimrails.org » Blog Archive » La diferencia entre “count” y “length” en Rails

  2. Be careful about this, though. Using length on a record that doesn’t have to be loaded in its entirety can be a huge performance problem. Suppose you have a model with a few million rows (not terribly rare in production systems); if you call length on this table, you will have these rows all loaded into an array, if you call count you will simply do a small SQL count statement. The latter will be significantly faster.

    The compromise? Use .size. Size will check if you have the array loaded, and use length if that’s the case; otherwise it uses count. It basically does the check for you.

Comments are closed.