相関サブクエリの難しさ

前書き

neat02です。
今回はSQLの相関サブクエリで、個人的に気になった点について執筆出来ればと思います。

環境

MySQL

相関サブクエリとは

相関サブクエリとは、外側のメインクエリと内側のサブクエリが関連している状態を指します。つまり、メインクエリからサブクエリで指定した条件を照らし合わせて、データを抽出します。 先に相関サブクエリを使ったクエリを提示します。
ここでは、E1がメインクエリ、E2がサブクエリです。

      #メインクエリ
      SELECT E1.gender, E1.emp_no, E1.birth_date
      FROM employees AS E1
      WHERE E1.birth_date = (
              #相関サブクエリ
               SELECT MIN(E2.birth_date)
               FROM employees AS E2
               WHERE E1.gender = E2.gender
            );

このクエリは、各性別の最年少の従業員の性別、従業員番号、生年月日を抽出します。 サブクエリで最年少(生年月日が遅い)人を選択して、再度WHERE句でメインクエリで性別を持っている人に一行ずつ検索をかけ、メインクエリにて最年少(生年月日が遅い)の人のデータを抽出します。
しかし、相関サブクエリには重大な欠点があります。
それは抽出に時間がかかることです。 レコードが少なければいいのですが、莫大な数のレコードであれば、 一行ごとに参照して抽出する相関サブクエリは相性最悪です。

そのため、このケースでは内部結合するのが手っ取り早いです。

      #メインクエリ
      SELECT E.gender, E.emp_no, E.birth_date
      FROM employees AS E
      #サブクエリ
      JOIN (
      SELECT gender, MIN(birth_date) AS min_birth_date
      FROM employees
      GROUP BY gender) AS G
      ON E.gender = G.gender AND E.birth_date = G.min_birth_date;

これは、サブクエリが各性別の最年少の従業員を選択します。
それをもとに、もとの「employees」テーブルと結合します。結合条件は、性別と生年月日が同じことです。これによりメインクエリで、各性別の最年少の従業員の性別、従業員番号、生年月日を選択できます。
実際のデータを用いると、相関サブクエリはデータの抽出が終了せず、内部結合による抽出は約30秒で終了しました。
適切なクエリを使えるようになりたいです。