609 文字
3 分
INNER JOIN vs EXISTS/WHERE

INNER JOINと EXISTS/WHERE の動作の違いを詳しく説明させていただきます。

1. 実行順序の基本的な考え方#

-- パターン1: EXISTS
FROM users u1
LEFT JOIN items i1 ON u1.item_id = i1.item_id
WHERE EXISTS (SELECT 1 FROM users u2 WHERE ...)
  • 実際の処理:
    1. u1の各行に対して
    2. EXISTSの条件を満たすu2の行を探す(相関サブクエリ)
    3. 条件を満たす行が見つかったらその行を保持
-- パターン2: INNER JOIN
FROM users u1
INNER JOIN items i1 ON u1.item_id = i1.item_id
INNER JOIN users u2 ON u1.user_id = u2.user_id
WHERE (条件)
  • 実際の処理:
    1. データベースエンジンが最適な結合順序を決定
    2. インデックスを使用して効率的に結合を実行
    3. WHERE条件で絞り込み

2. パフォーマンスの違い#

  • EXISTSの場合:

    • 相関サブクエリとして動作するため、外部クエリの各行に対してサブクエリを実行
    • ネステッドループのような動作になりやすい
  • INNER JOINの場合:

    • データベースエンジンが結合アルゴリズムを選択可能(ハッシュ結合、マージ結合など)
    • 一度の操作で結合を実行できる

3. 最適化の違い#

-- EXISTS版
SELECT u1.user_id
FROM users u1
WHERE EXISTS (
SELECT 1
FROM users u2
WHERE u2.user_id = u1.user_id
AND u2.category = 1111
)
  • 各u1の行に対して、u2をチェック
  • インデックスがあっても、繰り返し検索が必要
-- INNER JOIN版
SELECT u1.user_id
FROM users u1
INNER JOIN users u2
ON u1.user_id = u2.user_id
AND u2.category = 1111
  • データベースエンジンが最適な結合方法を選択可能
  • 例:ハッシュテーブルを作成して一度に結合

4. 実際のパフォーマンス比較方法#

EXPLAIN ANALYZE
SELECT ... /* それぞれのバージョン */
  • 実行計画と実際の実行時間を確認
  • 使用されるインデックス
  • 中間結果のサイズ
  • 実際のコスト

5. パフォーマンスに影響する要因#

  • テーブルサイズ
  • インデックスの有無
  • データの分布
  • 結合条件の選択性

6. 推奨アプローチ#

  1. まず実行計画を確認
EXPLAIN FORMAT=JSON
SELECT ... /* クエリ */
  1. 実際のデータで実行時間を計測
SET profiling = 1;
SELECT ... /* クエリ */
SHOW PROFILES;
  1. 結果を比較して最適な方法を選択

重要なポイントは:

  • INNER JOINは必ずしも「すべての結合を先に行ってからWHERE句で絞る」わけではありません
  • オプティマイザが実行時に最適な順序とアルゴリズムを選択します
  • 実際のパフォーマンスは、データ量や分布によって大きく変わる可能性があります

このため、本番環境に近いデータでの実際のテストが重要になります。