railsでbulk insertするときには今まではactiverecord-importが使うことが多かったと思いますが、
rails 6からはActiveRecord::Persistence#insert_allが追加されたので標準機能を使ってbulk insertを行うことができるようになりました。
実際に使ってみたので使い方とかメモしておきます。
使い方
使い方は簡単でbulk insartを行うModelのclassを対象にinsert_allを呼び出してあげるだけです。
class Entry < ApplicationRecord end now = Time.current Entry.insert_all([ { title: 'foo1', body: 'bar1', created_at: now, updated_at: now }, { title: 'foo2', body: 'bar3', created_at: now, updated_at: now }, ]) #=> Entry Bulk Insert (7.3ms) INSERT INTO "entries"("title","body","created_at","updated_at") VALUES ('foo1','bar1','2020-01-25 17:22:50.533182', '2020-01-25 17:22:50.533182'),('foo2','bar2','2020-01-25 17:22:50.533182', '2020-01-25 17:22:50.533182')
実行するとINSERT INTO table_name(column1, column2, ...) VALUES (value1, value2, ...)といったSQLが生成されて実行されます。
このように一つのINSERT文にまとめられるので、DBアクセスが少なくすみパフォーマンスがよくなりそうです👍(重複レコードがあった場合にはinsertがskipされます。)
※created_atとupdated_atを補完してくれないので自分で設定しないといけない点に注意です。実装をシンプルにしてパフォーマンスを担保するのとupdate_allの仕様に合わせているのが理由のようです🤔
https://github.com/rails/rails/issues/35493#issuecomment-470100313
ちなみにinsert_all!、upsert_allというメソッドも用意されていて、insert_all!を使うとレコード重複が発生した際にActiveRecord::RecordNotUniqueをraiseします🚨upsert_allを使うとレコードが重複が発生した場合に上書きされます💾(ON DUPLICATE KEY UPDATE or ON CONFLICTが実行される)
おわりに
rails 6から追加されたinsert_allの使い方書いてみました。
activerecord-importの方がエラーハンドリング周りとか良い感じにやってくれそうですが、シンプルなbulk insart機能をrails標準機能でシンプルに実装できるのは良いですね🙌