Rails Batch Processing Of Records For destroy_all
July 03, 2021
In Ruby on Rails, we use destroy_all
when we want to delete a collection of ActiveRecord::Relation
records.
Example:
Article.where(published: false).destroy_all
# Logs
# Article Load (0.3ms) SELECT "articles".* FROM "articles" WHERE "articles"."published" = #? [["published", 0]]
# TRANSACTION (0.1ms) begin transaction
# Article Destroy (0.5ms) DELETE FROM "articles" WHERE "articles"."id" = ? [["id", 1]]
# TRANSACTION (1.7ms) commit transaction
# TRANSACTION (0.1ms) begin transaction
# Article Destroy (0.5ms) DELETE FROM "articles" WHERE "articles"."id" = ? [["id", 2]]
# TRANSACTION (1.9ms) commit transaction
# Output
#=> [#<Article id: 1, title: "#0 Title", published: false>, #<Article id: 2, title: "#1 Title", published: false">]
As we notice above in the logs, all the records were loaded into the memory at a time and then DELETE
transaction was initiated for each record one by one.
Mark that
destroy_all
always returns the destroyed records as an array.
The initial load of all records at a time consumes memory unnecessarily which can be processed in batches.
To destroy records in batches, we can use in_batches
and destroy_all
methods defined in ActiveRecord::Batches::BatchEnumerator
.
Let's refactor above example to process it in batches:
# Ruby on Rails v6.1, v7.0
Article.where(published: false).in_batches(of: 100).destroy_all
When Ruby on Rails was getting ready for v7.0 release, there was a pull request that proposed to use in_batches
under the hood for destroy_all
method. However that pull request was reverted after initial merge since that might break many existing applications.
info@scriptday.com