609 文字
3 分
INNER JOIN vs EXISTS/WHERE
INNER JOINと EXISTS/WHERE の動作の違いを詳しく説明させていただきます。
1. 実行順序の基本的な考え方
-- パターン1: EXISTSFROM users u1LEFT JOIN items i1 ON u1.item_id = i1.item_idWHERE EXISTS (SELECT 1 FROM users u2 WHERE ...)
- 実際の処理:
- u1の各行に対して
- EXISTSの条件を満たすu2の行を探す(相関サブクエリ)
- 条件を満たす行が見つかったらその行を保持
-- パターン2: INNER JOINFROM users u1INNER JOIN items i1 ON u1.item_id = i1.item_idINNER JOIN users u2 ON u1.user_id = u2.user_idWHERE (条件)
- 実際の処理:
- データベースエンジンが最適な結合順序を決定
- インデックスを使用して効率的に結合を実行
- WHERE条件で絞り込み
2. パフォーマンスの違い
-
EXISTSの場合:
- 相関サブクエリとして動作するため、外部クエリの各行に対してサブクエリを実行
- ネステッドループのような動作になりやすい
-
INNER JOINの場合:
- データベースエンジンが結合アルゴリズムを選択可能(ハッシュ結合、マージ結合など)
- 一度の操作で結合を実行できる
3. 最適化の違い
-- EXISTS版SELECT u1.user_idFROM users u1WHERE EXISTS ( SELECT 1 FROM users u2 WHERE u2.user_id = u1.user_id AND u2.category = 1111)
- 各u1の行に対して、u2をチェック
- インデックスがあっても、繰り返し検索が必要
-- INNER JOIN版SELECT u1.user_idFROM users u1INNER JOIN users u2 ON u1.user_id = u2.user_id AND u2.category = 1111
- データベースエンジンが最適な結合方法を選択可能
- 例:ハッシュテーブルを作成して一度に結合
4. 実際のパフォーマンス比較方法
EXPLAIN ANALYZESELECT ... /* それぞれのバージョン */
- 実行計画と実際の実行時間を確認
- 使用されるインデックス
- 中間結果のサイズ
- 実際のコスト
5. パフォーマンスに影響する要因
- テーブルサイズ
- インデックスの有無
- データの分布
- 結合条件の選択性
6. 推奨アプローチ
- まず実行計画を確認
EXPLAIN FORMAT=JSONSELECT ... /* クエリ */
- 実際のデータで実行時間を計測
SET profiling = 1;SELECT ... /* クエリ */SHOW PROFILES;
- 結果を比較して最適な方法を選択
重要なポイントは:
- INNER JOINは必ずしも「すべての結合を先に行ってからWHERE句で絞る」わけではありません
- オプティマイザが実行時に最適な順序とアルゴリズムを選択します
- 実際のパフォーマンスは、データ量や分布によって大きく変わる可能性があります
このため、本番環境に近いデータでの実際のテストが重要になります。