♻️
[SQL] パフォーマンスチューニング countにソートは要らない
まず結果からお伝えすると、ある検索処理で 8秒かかっていたクエリが、53ms まで短縮 できました。その改善ポイントは「カウント時の余計なソートを消す」というシンプルな工夫でした。
発端: 13秒かかる重たいクエリ
ある画面で検索結果を表示する処理が 13秒 もかかっていました。
まずは定石通りインデックスを疑い、EXPLAIN
を確認。実際にインデックスが効いていない箇所があったので、インデックスを追加・クエリのリファクタリングを実施しました。その結果、処理時間は 13秒 → 8秒 に短縮。しかし依然として実用的ではありません。
Railsのコードを確認
対象箇所は Rails + Kaminari を使ったページング処理。該当コードは以下のようになっていました。
applicants = find_applicants(applicant_search_form)
applicants_length = applicants.count
applicants = applicants.includes(
:memos,
:occupation_categories,
:occupation_subcategories
).page(params[:page]).per(30).decorate
問題はこの行です:
applicants_length = applicants.count
この count
実行時に 余計な ORDER BY
が入ってしまい、全件ソートしてから件数を数える という無駄な処理が行われていました。
reorder(nil)
を活用
解決策: カウントにソートは不要なので、ソート指定を外せば良いのでは?と考えました。Rails では reorder(nil)
を指定することでソートを消せます。
修正後のコード:
applicants_length = applicants.reorder(nil).count
これだけでクエリが劇的に改善し、結果は 8秒 → 53ms に短縮。まさに桁違いのパフォーマンス改善となりました。
まとめ
-
count
は件数を数えるだけなので ソートは不要。 - Rails では
reorder(nil)
を指定することで余計なORDER BY
を消せる。 - 実際に 8秒 → 53ms という大幅な改善が得られた。
SQLチューニングというとインデックス設計やクエリ最適化が思い浮かびがちですが、ORMが生成するクエリのクセを理解して見直すことも重要です。ちょっとした一文の見直しで劇的に改善するケースがあるので、皆さんも似た場面に出会ったらぜひ reorder(nil)
を試してみてください。
Discussion