Railsで開発をしていると、必然的にActive Recordを使うことになると思います。
Active Recordを使うとSQLを書くことなくDB問い合わせができるので、便利な反面、
SQLや、キャッシュ、メモリを理解していないとパフォーマンスが悪くなってしまうことが
しばしばあります。
自分もまだ全然理解できていません。
今回1万件のデータをCSV生成する際に、関連モデルが多数あるモデルからall
で引っ張ってきた場合と、
関連テーブルとincludes
した場合のパフォーマンスを検証してみました。
ユーザーに、カテゴリテーブル、所属会社テーブルなど6つのテーブルが紐づいています。
Benchmarkを使う
RubyのライブラリであるBenchmarkを使います。
rails consoleでrequireして速度測定しました。
$ rails c [1] pry(main)> require 'benchmark' => true
includesした場合
今回は以下のようなscopeを作成しました。
scope :all_association_includes, -> do includes(:business_outline, :domicile_company, :job_category, :prefecture, :introducer_last_work_company) end
- クエリ数 = 6
result = Benchmark.realtime do User.to_csv('include_ver.csv') end User Load (327.4ms) SELECT "users".* FROM "users" WHERE ("users"."_at" IS NOT NULL) BusinessOutline Load (0.3ms) SELECT "business_outlines".* FROM "business_outlines" WHERE "business_outlines"."id" = 1 DomicileCompany Load (1.2ms) SELECT "domicile_companies".* FROM "domicile_companies" WHERE "domicile_companies"."id" = 1 JobCategory Load (1.1ms) SELECT "job_categories".* FROM "job_categories" WHERE "job_categories"."id" = 1 Prefecture Load (1.1ms) SELECT "prefectures".* FROM "prefectures" WHERE "prefectures"."id" = 1 DomicileCompany Load (0.1ms) SELECT "domicile_companies".* FROM "domicile_companies" WHERE "domicile_companies"."id" = 1 puts result => 33.34830200000215
includeしない場合
モデルをall
で全件取得。
User.all
result = Benchmark.realtime do User.to_csv('not_include_ver.csv') end クエリ数 = 尋常じゃない数 puts result => 151.05989799999952
結果
速度に5倍近く差が出ました。原因はクエリ数です。includesしない場合はUser一件取得ごとに関連テーブルのデータを取得するクエリが走りるのが原因です。
RailsやRubyを学ぶだけでなく、データベース周りも学習しないとですね。
コメントを残す