Loading
  • LIGHT

  • DARK

ROUTE

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

SQLサブクエリは遅い?JOIN・CTEとの違いと高速化のベストプラクティス

4

SQLサブクエリの正しい使い方|JOINやCTEとの違いを実行速度で徹底比較

SQLで複雑な処理を書いていると、「サブクエリを多用して遅い」「レビューでJOINを使えと言われた」といった経験はありませんか?

(SQLの基礎やエラー解決については初心者向けSQL講座|SELECT文の書き方と実行順を完全解説をご参照ください)

用語解説:サブクエリ
SQL文の中に入れ子として記述する別のSQL。主にSELECT・FROM・WHERE句などで使われ、複雑な条件や集計を実現できます。

用語解説:JOIN
複数のテーブルを関連付けてデータを取得するSQLの仕組み。リレーション(関係性)を明示でき、パフォーマンスや可読性に優れます。

用語解説:CTE(共通テーブル式)
WITH句で一時的なテーブルを定義し、複雑な処理を分割・再利用できるSQLの記法。可読性や保守性が向上します。

特にSES常駐の現場では、明確な設計思想やレビュー基準が共有されず、個人の実装に依存してしまうことも少なくありません。その結果、「動くけど、この書き方が本当に正しいのだろうか」「この書き方で評価されるのか」と不安を感じる場面も増えてしまいます。

この記事では、そんなモヤモヤを解消するために、SQLサブクエリの基礎から、JOINCTEとの比較、実行速度や保守性の観点での使い分けを整理します。

また、なぜこうした実装判断がキャリア評価や案件選定につながるのかも解説。記事を読み終える頃には、単なるエラー解消だけでなく、設計思想を理解し、自信を持ってレビューに臨める知識が身についているはずです。


1. SQLサブクエリの基礎と種類


SQLサブクエリの基礎と種類
図:SQLサブクエリの基礎と種類

SQLサブクエリとは、SQL文の中に入れ子として記述する別のSQLのことです。

(SQLのCASE式や条件分岐についてはSQL CASE式の使い方|SELECT・WHERE・UPDATEで条件分岐する書き方とつまずき解消実例をご参照ください)

用語解説:スカラーサブクエリ
単一の値(1セル)を返すサブクエリ。SELECT句で新しい列として使うことが多いです。

用語解説:相関サブクエリ
外側のクエリの値を参照し、行ごとに繰り返し実行されるサブクエリ。パフォーマンスに注意が必要です。

用語解説:非相関サブクエリ
外側のクエリとは独立して一度だけ実行されるサブクエリ。INやEXISTSでよく使われます。

大きく分けて、以下の3種類があります。

  • スカラーサブクエリ:単一の値を返すサブクエリです。SELECT (SELECT COUNT(*) FROM users) のように、列の一部として利用します。

    -- 例:各ユーザーの注文数を列として返す(スカラーサブクエリ)
    SELECT
      u.id,
      u.name,
      (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) AS order_count
    FROM users u;
    
  • 相関サブクエリ:外側のクエリの列を参照しながら、行ごとに繰り返し実行されるサブクエリです。パフォーマンスに影響しやすい傾向があります。

    -- 例:注文が存在するユーザーのみ抽出する(相関サブクエリ)
    SELECT
      u.name
    FROM users u
    WHERE EXISTS (
      SELECT 1
      FROM orders o
      WHERE o.user_id = u.id
        AND o.created_at > '2025-01-01'
    );
    
  • 非相関サブクエリ:外側のクエリとは独立しており、一度だけ実行されるサブクエリです。

    -- 例:有効なカテゴリを持つ商品のみ取得する(非相関サブクエリ)
    SELECT
      p.*
    FROM products p
    WHERE p.category_id IN (
      SELECT id FROM categories WHERE active = TRUE
    );
    

どの句で使えるか?

  • SELECT句:値を計算し、新しい列として返します。

    用語解説:SELECT句
    取得したい列や計算式を指定するSQLの基本構文。サブクエリや関数も利用可能です。

  • FROM句:派生テーブル(一時的なテーブル)として扱います。

    用語解説:FROM句
    データの取得元となるテーブルやサブクエリを指定する部分。JOINやCTEとも組み合わせます。

  • WHERE句INEXISTS と組み合わせて、条件判定に使います。

    用語解説:WHERE句
    データの絞り込み条件を指定するSQLの構文。サブクエリや比較演算子と併用します。


2. サブクエリを巡る“よくある失敗”とその背景

私たちは、サブクエリを直感的に使いやすいと感じがちです。しかし、ネストが深くなると可読性が低下し、チームメンバーのレビュー工数を増やしてしまうことがあります。

(SQLのパフォーマンス改善やJOINの使い方についてはSQL JOINの基本から実践まで|INNER・LEFT・RIGHT・OUTER JOINの違いをわかりやすく解説をご参照ください)

用語解説:ネスト
サブクエリや関数などを入れ子構造で重ねること。深くなるほど可読性や保守性が低下します。

失敗例(相関サブクエリによる性能悪化)

ユーザーごとの注文数を取得する際、相関サブクエリを使うとユーザー数分だけ内側が実行され、データ量が増えると極端に遅くなります。

-- 失敗例:ユーザーごとにサブクエリが実行される(相関サブクエリ)
SELECT
  u.id,
  u.name,
  (SELECT COUNT(*) FROM orders o WHERE o.user_id = u.id) AS order_count
FROM users u;

上記は小規模なら問題ないこともありますが、ユーザー数が多い環境では避けるべき書き方です。

改善例(集約してJOINする)

サブクエリを集約してからJOINすると、内側の処理は一度だけ実行されるため高速になります。

-- 改善例:集約してからJOINする
SELECT
  u.id,
  u.name,
  COALESCE(o.order_count, 0) AS order_count
FROM users u
LEFT JOIN (
  SELECT user_id, COUNT(*) AS order_count
  FROM orders
  GROUP BY user_id
) o ON o.user_id = u.id;

これが、レビューで「JOINに書き換えろ」と指摘される主な理由です。

なぜ相関サブクエリはパフォーマンスが落ちるのか?

相関サブクエリは、外側のクエリの行ごとに再実行されるため、データ量が多いと極端に遅くなる可能性があります。

用語解説:パフォーマンス
SQLやシステムの処理速度・効率。サブクエリやJOINの使い方で大きく変わります。

例えば、以下のコードを見てみましょう。

SELECT name
FROM users u
WHERE EXISTS (
    SELECT 1 FROM orders o WHERE o.user_id = u.id
);

この書き方では、ユーザー数 × 注文数の評価が発生し、大規模なデータベースではパフォーマンスが著しく低下することがあります。

可読性・保守性を軽視するリスク

  • レビュー工数が増え、開発全体のスピードが落ちる

  • 後任の担当者がコードの意図を読み解きづらい

  • 案件全体の信頼性が低下する

用語解説:可読性・保守性
可読性は「コードの読みやすさ」、保守性は「修正や拡張のしやすさ」。どちらも高いほどチーム開発で有利です。

SESの現場では、「動くコード」を書けることだけでなく、「誰が見ても理解できるコード」を書けることが評価につながります。


3. JOIN・CTE・ウィンドウ関数との比較

では、サブクエリは、他の手法と比べてどうでしょうか。

パフォーマンス比較

小規模データでは、サブクエリJOINに体感できるほどの差はほとんどありません。

一方で、大規模データでは、JOINCTEの方が一般的に高速です。特に、前述の相関サブクエリは極端に遅くなる傾向があります。

EXPLAIN を使って、実行計画を確認し、テーブルスキャンが増えていないか確認することが重要です。

用語解説:EXPLAIN
SQLの実行計画を表示するコマンド。どのようにテーブルを検索・結合するかを可視化し、パフォーマンス改善に役立ちます。

用語解説:テーブルスキャン
テーブル全体を1行ずつ検索する処理。インデックスがない場合に発生し、速度低下の原因になります。

可読性・レビュー観点からの比較

手法 可読性 実行速度 利用シーン
サブクエリ 小規模なら◯/大規模は× 条件判定に便利
JOIN 最適化されやすい リレーションの明示に有効
CTE 再利用性あり 複雑な処理の分割に有効

データベースごとの最適化差

  • MySQL:サブクエリの最適化が弱いため、JOINが推奨されます。

    用語解説:MySQL
    オープンソースの代表的なリレーショナルデータベース。サブクエリの最適化が他DBより弱い傾向があります。

  • PostgreSQLCTEの最適化に工夫が必要です。

    用語解説:PostgreSQL
    高機能なオープンソースDB。CTEやウィンドウ関数のサポートが充実しています。

  • Oracle:サブクエリ展開が強力で、性能劣化が少ない場合もあります。

    用語解説:Oracle
    商用DBの代表格。サブクエリや複雑なSQLの最適化が得意です。


4. サブクエリの理解がキャリアに直結する理由

単に「動くSQLを書ける」だけでは、エンジニアとしての評価は頭打ちになりがちです。

なぜJOINを選ぶのか、なぜCTEを使うのかを説明できると、設計力があると評価され、単価交渉でも有利に働きます。

案件ミスマッチを避けるためのスキルの見せ方

  • レジュメに「実行計画を考慮したSQL最適化経験」と記載する

  • コードレビューで「保守性を重視した設計方針」を言語化する

  • 「単価公開型SES」や「案件選定可」の企業にアピールする

サブクエリは、データベースの設計思想の基礎です。その理解は、評価基準になりやすく、将来アーキテクト候補を目指す上で避けて通れないポイントと言えます。


まとめ:今日からできる実践ステップ

最後に、サブクエリを使うか避けるかの簡単な判断フローと、学んだ知識をキャリアに活かすためのチェックリストをまとめます。

(SESエンジニアのキャリア戦略についてはSESポートフォリオ完全ガイド|5年後も選ばれるエンジニアのキャリア戦略と作り方をご参照ください)

用語解説:ウィンドウ関数
集計や順位付けなど、複数行をまたいだ計算を行うSQLの関数。CTEやサブクエリと組み合わせて使うことが多いです。

サブクエリを使う/避ける判断フロー

  1. 小規模データ → サブクエリを使っても問題ないケースが多い

  2. 大規模データJOINCTEを優先する

  3. 読みやすさ優先JOINCTEが推奨される

学びをキャリア評価に活かすチェックリスト

  • ✅ 実行計画(EXPLAIN)を読めますか?

  • JOINCTEで書き換えられますか?

  • ✅ データベースごとの最適化特性を理解していますか?

  • ✅ 設計意図を言語化できますか?

FAQ:よくある疑問

  • Q. SQLサブクエリはJOINより遅いの?どんな場合に?
    A. 相関サブクエリで顕著です。非相関やスカラーサブクエリではそこまで大きな差は出ません。

    用語解説:スカラーサブクエリ・相関サブクエリ
    スカラーサブクエリは単一値を返すもの、相関サブクエリは外側の値を参照し繰り返し実行されるものです。

  • Q. 相関サブクエリと非相関サブクエリの違いは?
    A. 外側のクエリの値を参照するかどうかが大きな違いです。

  • Q. サブクエリはどのデータベースでも同じ動き?
    A. 実装に違いがあります。MySQLは弱く、Oracleは強力です。

  • Q. サブクエリを使いすぎるとレビューで指摘されるのはなぜ?
    A. 可読性や保守性を損なう可能性があるためです。

  • Q. サブクエリよりCTEやウィンドウ関数を選ぶべきケースは?
    A. 複雑な集計や、複数の場所で再利用したい処理があるときです。

  • Q. サブクエリの知識はキャリア評価にどう影響する?
    A. 設計思想を理解していると評価が上がり、より上流の仕事を任されやすくなります。


最後に

SQLサブクエリは非常に便利ですが、万能ではなく「どの場面で使うか」を判断する力が重要です。

相関サブクエリを多用すれば速度低下を招き、レビューで指摘されることもあります。JOINCTEとの違いを理解し、実行計画を意識できることは、エンジニアとしての評価や案件選定の自由度につながります。

特にSES常駐の現場では、設計思想を説明できる人材が評価されやすく、キャリアの選択肢も広がります。

ぜひ今日学んだ知識を自分のコードやレビューに活かし、「動けばいい」から「納得できる設計」へと一歩進んでいきましょう。

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

DISCOVER MORE