背景
Rspecでテストを行う際にテストデータが大量に必要だったので、create_list
を使ってデータ作成していましたが、create_list
を使うよりbuild_list
したものをbulk_import
した方が高速化できると教えてもらいました。
bulk_import
はActiverecord-Import
というライブラリを入れるとバルクインサートができるようになるものです。
そこで、実際にどの程度高速化するのか気になったので、create_list
を使う場合とbuild_list
とbulk_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
を使って定数をスタブ化し、低い閾値にした方がテストが遅くならずに効率的に実施できるかと思います。