49hack

見習いエンジニアが魔法使いになるまで

大量のデータ挿入・更新にバルクインサート・バックアップデートを利用する

例えば以下の場合にSQLが1000回発行されます。

1000.times do
    Hoge.create(...)
end
# INSERT INTO hoge (...)
# INSERT INTO hoge (...)
# INSERT INTO hoge (...)
# ...

かなり非効率なのでbulk insertでSQLを1つにまとめて軽量化します。

Railsでbulk insertを実行するためにactiverecord-importというgemを利用します。

# Gemfile
gem 'activerecord-import'

すると、先ほどの処理は以下のように書けます。

hoge_list = []
1000.times do
    hoge_list << Hoge.new(...)
end
Hoge.import hoge_list
# INSERT INTO hoge (...), (...), (...), ...

すでにレコードが存在する場合は更新したい

レコードの存在をチェックして、存在する場合は更新、存在しない場合は挿入、ってことをRails側でやろうとするとSQLが大量に発行されて重い処理になってしまいます。

# こんな感じ
hoge_ids.each do |hoge_id|
    hoge = Hoge.find_by(id: hoge_id)
    if hoge.present?
        hoge.update(...)
    else
        hoge = Hoge.create(...)
    end
end

この場合は、on_duplicate_key_updateオプションを指定することで、MYSQL側で重複を検知して更新するようにします。

hoge_list = []
1000.times do
    hoge_list << Hoge.new(...)
end
# すでにレコードが存在する場合はname, contentカラムを更新するようにする
Hoge.import hoge_list, on_duplicate_key_update: [:name, :content]
# INSERT INTO hoge (...), (...), (...), ...

バルクインサート、バックアップデートでカンタン軽量化!お試しあれ\(^o^)/

参考