Loading
  • LIGHT

  • DARK

ROUTE

ルートゼロの
アクティビティ

SQL IN・EXISTS・JOINの違い徹底解説|安全で速い選び方と実践7チェック

2

「IN、EXISTS、それとも JOIN? どの書き方が安全で速いか、いま一度整理したい」
バッチ処理、API、除外条件、更新処理――ビジネス要件が多様化するほど、SQLの書き分けは “安全と性能” を左右する大切な選択になります。

本記事では、SQL初心者から中堅エンジニア、チーム開発者までを対象に、構文の違い/パフォーマンス/NULL安全性/実務応用を包括的に整理。コード例や判断ルール付きで紹介するので、次のレビューも、自信を持って説明できるようになります。


なぜ今、IN / EXISTS / JOIN の使い分けが重要か

モダンWeb/API/バッチ処理で求められるSQLの効率性

大規模データを扱うAPIやバッチが一般化した現代では、クエリの「ちょっとした違い」がパフォーマンスやレスポンス時間に直結します。副問い合わせを多用するサービスでは、IN/EXISTS/JOIN
の選択を誤ると、思わぬスローダウン・メモリ負荷が起きやすくなります。

NULL混在データや除外条件がバグを生む現実

DB設計の都合で「NULL許容カラム」が混在していたり、除外条件を使う場面も少なくありません。NOT IN のような書き方で NULL を含む結果を扱うと、意図しない全件除外などのバグにつながるケースもあります。

だからこそ、「どの構文が安全か」を見極める理解が必要です。

(NULL混在や除外条件のバグについては『SQL NULL完全攻略|IS NULL・COALESCEの使い分けとDB別バグ防止術5選』をご参照ください)


SQL構文の基本 — IN / EXISTS / JOIN の違い

IN の動作と向いている場面

  • 副問い合わせの結果を“リスト(集合)”として扱い、外側の値がその中に含まれるかをチェック
  • 用途:少数 or 固定値での絞り込み
  • メリット:構文が直感的・可読性が高い。副問い合わせが小さい場合は十分高速
  • 注意点:NULL混在時の誤動作、大量データ処理には不向き

-- IN のサンプル
SELECT name
FROM users
WHERE id IN (
  SELECT user_id
  FROM orders
  WHERE status = 'completed'
);
  

EXISTS の動作と向いている場面

  • サブクエリに “少なくとも1件” が存在するかをチェックする構文
  • 用途:存在チェック、関連テーブルにデータがあるか確認
  • メリット:メモリ効率良好・NULL安全・高速

-- EXISTS のサンプル
SELECT name
FROM users
WHERE EXISTS (
  SELECT 1
  FROM orders
  WHERE orders.user_id = users.id
    AND status = 'completed'
);
  

JOIN の基本と、なぜ JOIN も選択肢になるか

  • 用途:2つ以上のテーブルを結合して必要なカラムを取得
  • 適切なインデックス設計で高速処理も可能
  • 条件だけを見たい用途では EXISTS のほうが適していることも

-- JOIN のサンプル
SELECT users.name, orders.status
FROM users
INNER JOIN orders
  ON users.id = orders.user_id
WHERE orders.status = 'completed';
  

用語解説:IN
サブクエリの結果リストに、指定した値が含まれているかを判定するSQL構文。少数の値や固定リストの絞り込みに向いている。

用語解説:EXISTS
サブクエリに1件以上のデータが存在するかを判定するSQL構文。大規模データや存在チェックに強く、NULLにも安全。

用語解説:JOIN
複数テーブルを結合し、必要なカラムを取得するSQL構文。結合条件やインデックス設計がパフォーマンスに影響する。

用語解説:副問い合わせ(サブクエリ)
SQL文の中で、別のSELECT文を入れ子にして使う手法。INやEXISTSでよく利用される。

(サブクエリとJOIN・CTEのパフォーマンス比較については『SQLサブクエリは遅い?JOIN・CTEとの違いと高速化のベストプラクティス』をご参照ください)


パフォーマンス比較 — どの構文が速くなるか?

小規模データ/少数値リストなら IN が高速なケース

サブクエリ結果が少ないなら IN の方が直感的で、パフォーマンスも十分。

サブクエリが大きい or 存在チェックだけなら EXISTS/JOIN 有利なケース

マッチした時点で処理終了する EXISTS は、大規模テーブルでも効果的。

DBMS・インデックス状況で変わる実行計画 — 「絶対論」はない

構文による優劣ではなく、実行計画(EXPLAIN)とインデックス次第。

用語解説:インデックス
データベースの検索速度を向上させるための仕組み。適切な設計がパフォーマンスに直結する。

用語解説:実行計画(EXPLAIN)
SQLがどのように処理されるかをDBMSが示す設計図。パフォーマンス改善や安全な運用のために必ず確認する。

(SQLのパフォーマンス改善・チューニングについては『SQLチューニングとは?遅いSQLを最短で改善する3つの手順』をご参照ください)


NULL・除外条件・NOT IN/NOT EXISTS の注意点

NULL 混在時に起きる問題 — なぜ NOT IN は危険か

NOT IN では NULL の存在によってすべて false になる可能性がある。

安全な除外条件の書き方 — NOT EXISTS または LEFT JOIN + IS NULL

  • NOT EXISTS を使えば、NULLを含む場合でも安全に除外処理が可能
  • LEFT JOIN + IS NULL も有効(ただし結合性注意)

用語解説:NULL
データベースで「値が未設定・不明」を表す特殊な値。NOT INなどで誤動作の原因になるため注意が必要。


UPDATE/DELETE など更新系クエリでの使い分け

  • 更新系クエリでも EXISTS / NOT EXISTS を使えば安全で効率的
  • インデックス、ロック、トランザクションに注意
  • 本番前には EXPLAIN で実行計画を確認することが必須

実践・チェックリスト — 書いた SQL を見直す前の7つの確認項目 ✅

  1. サブクエリの規模は?(小=IN/大=EXISTS)
  2. NULL混在や除外条件は?(NOT EXISTSまたはLEFT JOIN)
  3. 結合が必要か?(必要=JOIN/不要=EXISTS)
  4. 更新/削除クエリ?(安全な書き方か確認)
  5. インデックス状況は?
  6. 実行計画を確認したか?
  7. 可読性とレビュー説明性は担保されているか?

よくある疑問(FAQ)

  • IN と EXISTS、どっちが速い?
    → データ量・DB環境依存。EXPLAINで確認。
  • NULLが混在する場合は?
    → NOT IN は避ける。NOT EXISTSやJOINが安全。
  • JOINが有利な場面は?
    → 結合結果が必要な場合。
  • UPDATE/DELETEでも使える?
    → 使える。ただし実行計画とロック競合に注意。

まとめ — あなたのプロジェクトでどう選ぶかの判断基準

  • 小規模データ or 固定リスト → IN
  • 存在チェック → EXISTS
  • 除外 or NULL対策 → NOT EXISTS / LEFT JOIN + IS NULL
  • 更新系 or 結合データ取得 → JOIN

最終判断は実行計画とインデックスを必ず確認すること。

もっとルートゼロを知りたいなら

DISCOVER MORE