♻️

[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) を試してみてください。

Archibase Tech Blog

Discussion