Why to use find_each instead of all in Ruby on Rails

In Ruby on Rails, there are two main methods for retrieving all records from a model: all and find_each. Both methods return an ActiveRecord::Relation, but they have different performance characteristics.

The all method

The all method returns all records from a model in a single query to the database. This can be efficient if the number of records is small, but it can be inefficient if the number of records is large.

For example, the following code uses the all method to retrieve all users from the database:

1
users = User.all

Considering a database with 1 million records, it will need to load all 1 million records into memory at once. This can be a significant memory burden for the application, and it can also lead to performance problems if the application does not have enough memory.

The find_each method

The find_each method loads records into memory one at a time. This can be more efficient if the number of records is large, as it prevents all records from being loaded into memory at once.

For example, the following code uses the find_each method to retrieve all users from the database:

1
2
3
users = User.find_each do |user|
  # ...
end

The batch_size option can be used to control the number of records that are returned in each batch.

For example, the following code uses the batch_size option to retrieve all users from the database in batches of 100 records:

1
2
3
users = User.find_each(batch_size: 100) do |user|
  # ...
end

If the application uses the find_each method with a batch_size of 100, it will only need to load 100 records into memory at a time. This can significantly improve performance and memory usage.

This code will execute 100 queries to the database, one for each batch of 100 records.

The batch_size option can also be used to improve performance for queries that are filtered or sorted:

1
2
3
users = User.where(location: "United States").find_each(batch_size: 100) do |user|
  # ...
end