LoginSignup
99
61

More than 3 years have passed since last update.

Rails6.0におけるbulk insert

Last updated at Posted at 2019-05-06

Rails6.0では、bulk insert用にinsert_all insert_all! upsert_allという3つのメソッドがActiveRecordに追加されました。

Rails5.2までのbulk insertはactiverecord-importというGemを使うのが主流でしたが、それに置き換わるものになりそうです。

1. insert_allメソッド

insert_allメソッドは、その名の通り複数件のレコードを一括でINSERTします。

rails/activerecord/lib/active_record/persistence.rb
def insert_all(attributes, returning: nil, unique_by: nil)
  InsertAll.new(self, attributes, on_duplicate: :skip, returning: returning, unique_by: unique_by).execute
end

on_duplicate: :skipとなっているため、id(主キー)が重複しているレコードはスキップされます。
例えば

User.insert_all([
  { id: 1, name: 'Taro', age: 20 },
  { id: 1, name: 'Jiro', age: 21 }
])

とやると、2件目の{ id: 1, name: 'Jiro', age: 21 }は無視されて、INSERTされません。

1-1. returningオプション

returningは、PostgreSQLにのみ有効なオプションです。
返り値として得られる、INSERTに成功したレコードの属性を指定することができます。
デフォルトでは、id(主キー)が返って来ます。
例えば

rails/activerecord/lib/active_record/persistence.rb
returning: %w[ id name ]

と指定すると、idnameが返ってきます。

1-2. unique_byオプション

unique_byは、PostgreSQLとSQLiteにのみ有効なオプションです。
デフォルトでは、id(主キー)のみが重複しているとスキップされます。unique_byオプションをつけると、重複でスキップするカラムを配列によって追加で指定できます。

rails/activerecord/lib/active_record/persistence.rb
unique_by: { columns: %w[ isbn ] }

以下のようにcolumns:where:を組み合わせることで、部分インデックスを指定することもできます。

rails/activerecord/lib/active_record/persistence.rb
unique_by: { columns: %w[ isbn ], where: "published_on IS NOT NULL" }

2. insert_all!メソッド

insert_all!メソッドは、insert_allメソッドと同様に複数件のレコードを一括でINSERTします。
insert_allメソッドとの違いは、id(主キー)が重複しているとスキップするのではなくエラーを返します。

rails/activerecord/lib/active_record/persistence.rb
def insert_all!(attributes, returning: nil)
  InsertAll.new(self, attributes, on_duplicate: :raise, returning: returning).execute
end

on_duplicate: :raiseとなっているため、id(主キー)が重複しているとraise ActiveRecord::RecordNotUniqueのエラーを返します。
例えば

User.insert_all!([
  { id: 1, name: 'Taro', age: 20 },
  { id: 1, name: 'Jiro', age: 21 }
])

とやると、2件目の{ id: 1, name: 'Jiro', age: 21 }raise ActiveRecord::RecordNotUniqueのエラーが発生します。

2-1. returningオプション

1-1.returningオプションと同じです。

3. upsert_allメソッド

upsert_allメソッドは、まだ存在しないレコードならINSERT、既に存在するレコードならUPDATEします。

rails/activerecord/lib/active_record/persistence.rb
def upsert_all(attributes, returning: nil, unique_by: nil)
  InsertAll.new(self, attributes, on_duplicate: :update, returning: returning, unique_by: unique_by).execute
end

on_duplicate: :updateとなっているため、id(主キー)が重複しているとupdateします。

3-1. returningオプション

1-1. returningオプションと同じです。

3-2. unique_byオプション

1-2. unique_byオプションと同じです。

99
61
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
99
61