あきろぐ

いろいろめもするよ🐈🐈🐈

FactoryBotでデータを大量に作成する2パターンの速度比較をしてみた

背景

Rspecでテストを行う際にテストデータが大量に必要だったので、create_listを使ってデータ作成していましたが、create_listを使うよりbuild_listしたものをbulk_importした方が高速化できると教えてもらいました。

bulk_importActiverecord-Importというライブラリを入れるとバルクインサートができるようになるものです。

github.com

そこで、実際にどの程度高速化するのか気になったので、create_listを使う場合とbuild_listbulk_importを使う場合で速度検証してみました。

検証内容

  • 作成するデータ量は、5、10、100、200、300の5パターンとする
  • 計測するのはデータを作成するのにかかった時間(Time.currentをデータ作成前後で取得し差分とる)
  • 各パターンで5回の速度を計測したものの平均値を算出し、比較する
# create_listを使う場合
create_list(:article, 5)

# build_listとbulk_importを使う場合
Article.bulk_import build_list(:article, 5)

検証結果

データ量が300になると、2秒程度の差になりました。想定よりそこまで差がつかない結果となりました。

回数 create_listの場合(s) build_list & bulk_importの場合(s)
5 0.3082704 0.2623282
10 0.7855298 0.6998084
50 3.892437 3.3376432
100 7.7685084 7.0694844
200 15.8506986 14.4952762
300 22.8225408 20.3966336

Rspecのプロファイリングを有効にする--profileオプションを使ってテスト実行にかかった時間でも比較してみました。

※ 300データのみで計測(5回平均)

# rspecのテストはAPIレスポンスが200を返すかどうかの確認のみ
# 細かい部分は省略
subject { get articles_path }

it 'return 200' do
  subject
  expect(response.status).to eq 200
end
回数 create_listの場合(s) build_list & bulk_importの場合(s)
300 24.358 19.116

テストの実行時間でみると約5秒の差がつきました。

どちらも大きな差がでるほどではありませんでしたが、これが複数のexampleだったり大量のテストデータを何回も作成する場合であれば、大きな差になりそうです。

まとめ

どちらを使っていても大量にデータを作成する場合は、数に比例して遅くなってしまうので、例えばデータの数を閾値としてつかっていて、定数化しているならstub_constを使って定数をスタブ化し、低い閾値にした方がテストが遅くならずに効率的に実施できるかと思います。

rubydoc.info