Madogiwa Blog

主に技術系の学習メモに使っていきます。

rails 6の新機能`insert_all`を試してみたのでMEMO📝

railsでbulk insertするときには今まではactiverecord-importが使うことが多かったと思いますが、 rails 6からはActiveRecord::Persistence#insert_allが追加されたので標準機能を使ってbulk insertを行うことができるようになりました。

github.com

実際に使ってみたので使い方とかメモしておきます。

使い方

使い方は簡単で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_atupdated_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標準機能でシンプルに実装できるのは良いですね🙌

参考

qiita.com