Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does ActiveRecord perform inserts/deletes in bulk when inside a transaction?

What I need:

  1. ensuring atomic updates (no record can gets processed 2 times)
  2. bulk deletion for all 1000 rows selected

@queue = Queue.where("col = 1").limit(1000)
ids = []
@queue.each do |row|
    Queue.do_something(row)
    ids << row.id
end

Queue.delete_all("id in (#{ids.join(',')}) ")

IS THE SAME AS

Queue.transaction do
    @queue.each do |row|
        Queue.do_something(row)
        Queue.delete(row.id)
    end
end
like image 306
newx Avatar asked May 07 '11 17:05

newx


People also ask

How does ActiveRecord transaction work?

Transactions in ActiveRecord Every database operation that happens inside that block will be sent to the database as a transaction. If any kind of unhandled error happens inside the block, the transaction will be aborted, and no changes will be made to the DB.

How to bulk insert in Rails?

Bulk inserts can be performed using newly added methods: insert_all, insert_all! and upsert_all. All of these new methods allow the insertion of multiple records of the same model into the database.

What is ActiveRecord?

Active Record is the M in MVC - the model - which is the layer of the system responsible for representing business data and logic. Active Record facilitates the creation and use of business objects whose data requires persistent storage to a database.


2 Answers

For inserts:

ActiveRecord does not perform a bulk insert when using a transaction. However it does speed things up a bit since it is using a single transaction to execute all INSERT statements as opposed to one transaction per INSERT statement otherwise.

So:

Queue.transaction do 
  @queue.each do |row|
    # an INSERT is done here
  end
end

is going to be faster than:

@queue.each do |row|
  # an INSERT is done here
end

For more info on how to really do bulk inserts, check out this article.

For deletes:

The ActiveRecord delete_all call is one single SQL DELETE statement, so I guess you could consider this as a bulk delete (no need to use a transaction here since it's already encapsulated in one transaction by ActiveRecord). This is not the case when calling delete on each record, which will result in multiple SQL DELETE statements, thus multiple transactions initiated and committed and overall slower performance.

like image 180
mbreining Avatar answered Oct 30 '22 18:10

mbreining


I suggest you take a look at ActiveRecord Import: https://github.com/zdennis/activerecord-import.

I'm using this tool to insert between 10,000 and 100,000 rows of data.

books = []
10.times do |i| 
  books << Book.new(:name => "book #{i}")
end
Book.import books

If you're using MySQL, it also supports ON DUPLICATE KEY UPDATE so you can intelligently insert new / update old rows. https://github.com/zdennis/activerecord-import/wiki/MySQL:-On-Duplicate-Key-Update-Support

like image 25
jwg2s Avatar answered Oct 30 '22 20:10

jwg2s