概要
- RubyにおいてCSVデータをDBに挿入する際の手法による速度の違いをベンチマーク
- CSVデータのインポート処理は業務系のWebアプリケーションを構築する際にはほぼ必ず必要となる機能なので感覚地として掴んでおくことが目的です。
ベンチマーク対象のアプリケーション
- https://postcode.teraren.com/ のデータ洗い替えの処理
- 郵便局のサイトから、郵便番号データと、事業所のデータをダウンロード
- importの処理流れ
- 郵便番号のデータで洗替
- 郵便番号のデータを処理して、建物ごとに郵便番号をまとめて洗い替え
- 事業所のデータを洗替
この処理を運用中のサービスでは月初に自動で行っています。
Rails6でアプリケーションは書かれていますが、Rails5の場合も考慮してbulk insertにはactiverecord-importを使います。どちらを使ってもほぼ速度は変わらないようです。
データ量は、郵便番号のデータが124,568レコード、事業所のデータが22,371レコードです。
Ruby 3.0.0 + Rails 6.1.3
アプローチ
データをインポートする際に、どの程度抽象的なプログラミングを行うかがキーになってきます。低レイヤーで書けば書くほど速度は早いけど、ビジネスロジック上で面倒を見ないといけないことが多くなります。
主に悩む選択肢は以下です。
- ActiveRecordオブジェクトをつかつか、Hashを使うか? (ActiveRecord VS Hash)
- bulk insertを使うかどうか? (insert VS bulk insert)
それぞれのパターンで計測してみます。
ベンチマーク
以下のパターンでとりました。
- Hash VS ActiveRecord
- insert VS bulk insert
一応、比較のためにRails6のinsert_allのベンチマークも取ってみましたが、importよりかなり速いです。
activerecord-importはデフォルトでvalidateがかかりますが、ActiveRecord 6のinsert_allはvalidateは走りらないことが速度の差かと思います。DBへのアクセスが発生するようなvalidationは行っていませんが塵も積もれば山となる感じかと思います。
考察
- ActiveRecord VS Hashの結果
- Hashのほうが20秒ぐらい速い。=約22%速い。
- insert VS bulk insert
- bulk insertのほうが約220秒速い。=約74%速い。
注意:前処理の時間(約10秒)を含んだベンチマークなので、実装コード部分だけで考えれば、上記の表記よりずっと速い。
まとめ
- CSVをインポートする際は以下の組み合わせが一番速い
- Hashの配列を作る
- Rails6のinsert_allを使う
- もともとは110秒かかっていた処理を76秒にしました。=約30%高速化。
- おもな変更点は2つ。ActiveRecordのインスタンスを作るのをやめて、import gemをinsert_allに変更。
Comments