0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

多数テーブルJOIN × ソート × ページングは危険!パフォーマンス改善のベストプラクティス

Posted at

🚀 パフォーマンス改善のためのSQL戦略

業務システムやポータルサイトのバックエンドでは、検索画面で大量のデータを結合し、条件で絞り込み、並べ替え・ページングする構成がよくあります。

SELECT * 
FROM staff
JOIN store ON ...
JOIN area ON ...
LEFT JOIN video ON ...
WHERE 条件
GROUP BY staff.id
ORDER BY staff.updated_at DESC
LIMIT 0, 30;

このような「複数のテーブルをJOINして、ソートして、LIMITする」SQLは、一見シンプルに見えても、パフォーマンスがボトルネックになりやすい構成です。

この記事では、こういったクエリがなぜ遅くなるのかどう改善すれば良いのかを、実例をもとに分かりやすく解説します。


💥 問題となる典型パターン

🛑 よくある構造

  • 10以上のテーブルをJOIN(INNER / LEFT混在)
  • 複雑なWHERE条件(サブクエリ、OR、CASE文)
  • GROUP BYとORDER BYが混在
  • LIMIT / OFFSET でページング

🔧 実際の EXPLAIN の一部(例)

table type rows Extra
staff ref 1200 Using index condition
video ref 5000 Using where
area const 1
store ref 3000 Using where; Using temporary; filesort

❗ 問題ポイント

  • Using temporaryUsing filesort
    → ソートのためのテンポラリテーブルとファイルソートが発生
  • LIMITが適用される前に、全ての行に対してソートが走る
  • LEFT JOIN先の条件が複雑でインデックスが効きづらい

⚠️ なぜ遅くなるのか?

  1. JOINで絞り込み前の行数が爆発的に増える
  2. 全行をORDER BYでソート
  3. LIMITは最後に適用されるため、途中の行もすべて評価対象
  4. MySQL/MariaDBはこのパターンに非常に弱い
    → 特にOFFSETが大きくなるとパフォーマンスが劣化

✅ ベストプラクティス:2段階取得戦略

🥇 ステップ1:IDだけ先に取得(軽量)

SELECT staff.id
FROM staff
JOIN store ON ...
WHERE 条件
ORDER BY staff.updated_at DESC
LIMIT 0, 30;
  • この段階では、必要なIDだけを取得
  • 重いJOINやLEFT JOINは後回し!

🥈 ステップ2:詳細情報を取得(JOIN)

SELECT s.*, v.*, a.*
FROM staff s
LEFT JOIN video v ON ...
LEFT JOIN area a ON ...
WHERE s.id IN (1, 2, 3, ..., 30);
  • 件数が少ないため、JOINしても高速
  • ORDER BYは不要(前段で完了しているため)

🧪 パフォーマンス比較

パターン 実行時間
1段階フルJOIN 1.4秒
2段階戦略 0.12秒
  • 約10倍以上の高速化を実現!
  • 特に大きなOFFSETになると差は指数的に拡大

✨ 補足:さらに高みを目指すなら

  • WITH句で一時的なサブクエリ(MariaDB 10.2+)
  • IDソート用インデックスを作る(例:(updated_at, id)
  • OFFSETを使わず、「カーソル方式(seek)」でページング
WHERE (updated_at, id) < (?, ?)

🎯 まとめ

問題 解決策
JOINが多くソートが重い IDだけ先に取得し、詳細は後段で
ソートに時間がかかる ソート対象を最小限に絞る
LIMIT OFFSETが遅い IDベースのカーソル方式でページング

📘 最後に

JOIN・ソート・ページングはWebシステムの根幹ですが、正しい戦略で設計しないとスケールしないクエリになります。

まずはIDだけ取る」「JOINを遅延する
この2段階戦略は、データ量が増えたときにも強い構造です。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?