Railsアプリケーションでバルクインサート(複数のレコードを一括でインサートする方法)を実現する場合、Rails 6以前はactiverecord-importを利用する必要がありました。
Rails 6からはバルクインサートを実現するinsert_allというメソッドが標準で利用できます。
今回はinsert_allの利用方法について紹介します。
一般的なデータの作成方法
Userモデルに10,000件データを用意すると仮定します。
1件ずつデータを作成する場合は以下のようになります。
10_000.times do |n|
User.create!(
name: "user_#{n+1}"
)
}
insert_allを利用したデータの作成方法
insert_allを利用して10,000件データを作成する場合は以下のようになります。
insert_allではcreated_atとupdated_atも明記する必要があります。
users = []
10_000.times do |n|
time = Time.current
users << { name: "user_#{n+1}", created_at: time, updated_at: time }
end
User.insert_all users
ベンチマークの比較
insert_allの効率を確認するため、1万件データを作成する場合のベンチマークを計測してみます。
ベンチマークテストはRuby標準のBenchmarkモジュールを利用します。
Benchmarkモジュールの利用方法についてはRuby標準のBenchmarkモジュールを利用したベンチマークの実行・確認方法で紹介をしています。
seeds.rb
Benchmark.bm(20) do |x|
x.report("baseline") {
10_000.times do |n|
User.create!(name: "user_#{n+1}")
end
}
x.report("insert_all") {
users = []
10_000.times do |n|
users << { name: "user_#{n+1}", created_at: Time.current, updated_at: Time.current }
end
User.insert_all users
}
end
結果は以下の通りです。insert_allのほうが処理時間が短いです。
$ rails db:seed
user system total real
baseline 33.414657 4.211116 37.625773 ( 80.747791)
insert_all 1.139993 0.112310 1.252303 ( 1.365058)
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!