「サブクエリ」タグアーカイブ

SQL:NOT IN と NOT EXISTS の違いとパフォーマンス比較

SQLでサブクエリを使って除外条件を指定する際に利用される「NOT IN」と「NOT EXISTS」。両者の動作の違いやNULLの扱い、パフォーマンス差を実例付きで徹底解説します。

EXISTSANSI SQL(国際標準SQL)に含まれる構文 のため、
ほぼすべてのリレーショナルデータベースで利用できます。
古いバージョンの一部DBを除き、標準構文として移植性が非常に高いのが特徴です。

1. NOT IN と NOT EXISTS の基本構文

構文例説明
NOT INSELECT * FROM A WHERE ID NOT IN (SELECT ID FROM B);サブクエリの結果に含まれないIDを抽出
NOT EXISTSSELECT * FROM A WHERE NOT EXISTS (SELECT 1 FROM B WHERE A.ID = B.ID);Bに同じIDが存在しない場合のみAを取得

ポイント:

  • 両者とも「除外」目的だが、評価タイミングとNULL処理が異なる。


2. 動作の違い(NULLの扱いに注目)

条件NOT INの結果NOT EXISTSの結果
サブクエリにNULLが含まれるすべての行が除外される正常に比較できる
サブクエリが空(0件)全件取得される全件取得される

理由:
NOT IN は内部的に「A.ID <> B.ID」を繰り返すような処理を行うため、NULLが含まれると比較結果がUNKNOWNとなり、全体が評価されなくなる。
一方、NOT EXISTS行ごとに存在チェックを行うため、NULLの影響を受けない。


3. 実行結果の比較例

以下の例を見てみましょう。

テーブルA

ID NAME
1 田中
2 鈴木
3 佐藤

テーブルB

ID
1
NULL

4. パフォーマンスの違い

比較項目NOT INNOT EXISTS
NULLの影響受ける受けない
実行計画(最適化)インデックス利用されにくい場合あり最適化されやすい
大量データ時の効率遅くなるケースありより安定して高速
Oracleの最適化傾向半結合(Anti-Join)に変換されることあり同様に最適化される

実測例(概略)

件数NOT IN所要時間NOT EXISTS所要時間
1万件0.25秒0.20秒
10万件3.1秒1.8秒

※ 実測環境:Oracle 19c、インデックスあり、CPU 4コア相当


5. どちらを使うべきか

条件推奨句
サブクエリにNULLが含まれる可能性ありNOT EXISTS
データが小規模でNULLなしどちらでも可
大規模データ・実行計画を重視NOT EXISTS(推奨)
可読性を優先NOT EXISTS のほうが誤動作が少ない

6. まとめ

観点内容
ANSI SQL対応○(どのDBでも使用可能)
実行パフォーマンスDBごとに最適化される(MySQL 8以降で特に改善)
推奨度高い(NOT INより安全で移植性が高い)
注意点MySQL 5.x 以前では最適化が弱いケースがある

✔ 結論:
除外条件を指定する場合は、基本的に「NOT EXISTS」を使う方が安全で高速です。
ただし、NULLが確実に存在しないことが保証される小規模データではNOT INも選択肢になります。

SQL:サブクエリの使い方を徹底解説!実例で学ぶネストされたSELECT文

はじめに

SQLを学んでいると「サブクエリ(副問い合わせ)」という言葉を耳にすることが多いでしょう。
サブクエリは、SELECT文の中にさらにSELECT文をネスト(入れ子構造)して使う機能です。
複雑な条件指定や集計処理をシンプルに書けるため、業務システムやデータ分析で頻繁に活用されます。

この記事では、サブクエリの基本から実践的な使い方まで、実例を交えて徹底解説します。


サブクエリとは?

**サブクエリ(Subquery)**とは、SQL文の中に埋め込まれるSELECT文のことです。
通常のSQL文の一部として利用され、主に次のような用途があります。

  • WHERE句での条件指定

  • FROM句での仮想テーブル生成

  • SELECT句での派生列計算


サブクエリの基本構文

サブクエリの基本的な形は以下の通りです。

SELECT 列名 FROM テーブル WHERE 条件式 (SELECT 列名 FROM 別テーブル WHERE 条件);
ポイントは、サブクエリの結果が単一値・リスト・テーブルとして返ることです。

用途によって、スカラサブクエリ、行サブクエリ、テーブルサブクエリと呼ばれることもあります。


例1:WHERE句でのサブクエリ

もっともよく使われるのが WHERE句での利用 です。
例えば「平均給与より高い社員を取得する」場合は次のように書けます。

  • サブクエリ (SELECT AVG(給与) FROM 社員) で平均給与を取得

  • メインクエリで給与がそれを上回る社員を抽出


例2:IN句とサブクエリ

複数の値を条件にする場合は IN句 を利用します。

  • サブクエリで特定の日に注文された商品IDを取得

  • メインクエリでその商品情報を表示


例3:FROM句でのサブクエリ(派生テーブル)

FROM句でサブクエリを使えば、仮想テーブルを作成して結合や集計が可能です。

  • サブクエリで部署ごとの平均給与を計算

  • メインクエリで平均給与が30万円を超える部署を抽出


例4:SELECT句でのサブクエリ

SELECT句にサブクエリを埋め込むことで、計算列を動的に追加できます。

 
SELECT 社員名, (SELECT 部署名 FROM 部署 WHERE 部署.部署ID = 社員.部署ID) AS 部署名 FROM 社員;
  • 社員ごとに部署名をサブクエリで取得

  • JOINを使わずにシンプルに表記可能(ただしパフォーマンス注意)


サブクエリを使うときの注意点

  1. パフォーマンスに注意
    ネストが深すぎると処理速度が落ちる場合があります。JOINやCTE(共通テーブル式)で置き換えを検討しましょう。

  2. 返却される値の型に注意
    単一値を期待しているのに複数行が返るとエラーになります。

  3. 読みやすさを意識
    サブクエリは便利ですが、複雑になると可読性が低下します。適切にインデントを整えるのが重要です。

  4. DBMS別:サブクエリ対応表
    DBMSWHERE句でのサブクエリFROM句でのサブクエリSELECT句でのサブクエリ相関サブクエリ備考
    Oracle○ 完全対応○ インラインビュー○ 利用可○ 高性能大規模業務で多用
    MySQL○ (v4.1以降対応)○ 利用可○ 利用可△ パフォーマンス注意古いバージョンでは非対応
    PostgreSQL○ 標準準拠○ 利用可○ 利用可○ 高性能複雑な分析処理に強い
    SQL Server○ 完全対応○ 利用可○ 利用可○ ただし過剰利用注意実行計画が膨らむことあり

まとめ

  • サブクエリはSQL文の中でネストされたSELECT文

  • WHERE、FROM、SELECTなど多くの場面で利用可能

  • 集計や複雑な条件指定をシンプルに書ける

  • パフォーマンスと可読性に注意が必要

サブクエリをマスターすることで、SQLの表現力が大幅に広がります。
まずはシンプルなWHERE句から練習し、徐々に複雑なケースに挑戦してみましょう!

SQL:IN句からEXISTS句への変換方法

IN句をEXISTS句へ変換するとパフォーマンスが向上すると言われることがあるので

IN句からEXISTS句への変換例をメモしておきます。

サンプルテーブル

以下の商品テーブル「goods」と属性コードテーブル「type_code」を元に説明します。

    商品テーブル「goods」属性コードテーブル「type_code」
    ""

IN句を使用したSQL例

商品テーブル「goods」のtype_codeが ‘101’で属性コードテーブル「type_code」にも存在する商品名を取得する例となります。

EXISTS句を使用したSQL例

WHERE句後の「tc.code IN」を「EXISTS」に変更し、「AND type_code = tc.code」を追加しただけです。

出力結果(IN句、EXISTS句)

IN句、EXISTS句どちらの場合も以下の結果となります。

NOT EXISTS句を使用したSQL例

EXISTS句は使い慣れてないと今一つ分かりにくい気がするので、上記のEXISTSをNOT EXISTSで実行してみた例も記載しておきます。なんとなくEXISTSがどういう結果を出力しているかわかるかも。。

出力結果(NOT EXISTS句)

NOT EXISTS句の結果は以下となります。


補足

本稿では、 IN句 から EXISTS句 への変換例およびその基本的な使い分けを紹介しましたが、実運用においては以下の点にもご留意ください。

  • データベース製品(たとえば PostgreSQL/Oracle Database/MySQL)やバージョンによって、IN句とEXISTS句の内部実行プランや最適化状況が異なるため、単純に「INは遅い」「EXISTSの方が速い」と一律判断するのは危険です。

  • 実際には、サブクエリの対象件数・インデックス構成・統計情報の鮮度などがパフォーマンスに大きく影響します。EXISTSに変えたからといって必ずしも高速化するとは限りません。

  • また、可読性・保守性の観点からは「どちらが読みやすいか・将来変更しやすいか」も考慮に入れるべきです。たとえば、複雑な条件・結合・集計を伴うSQLでは、意図が明確な記述を優先したほうがトラブルを防げます。

  • 最後に、SQLのチューニングは「手段」ではなく「目的」—つまり、「実際の業務で期待されるレスポンスタイムを満たしているか」「運用負荷を適切にコントロールできているか」という観点が最も重要です。この点を忘れず、必要に応じて実行計画の確認やプロファイリングを実施してください。

引き続き、SQL設計・実装・運用の改善にお役立ていただければ幸いです。
今後も他の観点(たとえば JOINの最適化/ウィンドウ関数の活用/データ量に対するスケーリング)についても、機会を改めてご紹介したいと思います。