Documentation Home
MySQL 5.6 リファレンスマニュアル
Download this Manual
PDF (US Ltr) - 26.8Mb
PDF (A4) - 26.9Mb
HTML Download (TGZ) - 7.1Mb
HTML Download (Zip) - 7.2Mb


MySQL 5.6 リファレンスマニュアル  /  制約と制限  /  サブクエリーの制約

D.4 サブクエリーの制約

  • IN に対するサブクエリーの最適化は、= 演算子または IN(value_list) 演算子の場合のようには効果的ではありません。

    IN サブクエリーのパフォーマンスが不十分である一般的な例では、サブクエリーが少数の行を返すのに対し、外部クエリーがサブクエリーの結果と比較して多数の行を返す場合があります。

    この問題は、IN サブクエリーを使用するステートメントでは、オプティマイザが相関サブクエリーに書き換えることにあります。非相関サブクエリーを使用する次のステートメントについて説明します。

    SELECT ... FROM t1 WHERE t1.a IN (SELECT b FROM t2);

    オプティマイザがステートメントを相関サブクエリーに書き換えます。

    SELECT ... FROM t1 WHERE EXISTS (SELECT 1 FROM t2 WHERE t2.b = t1.a);

    内部クエリーと外部クエリーがそれぞれ M 行と N 行を返す場合、実行時間は、非相関サブクエリーの場合の O(M+N) ではなく、O(M×N) になります。

    つまり、IN サブクエリーは、このサブクエリーが返す値と同じ値をリストする IN(value_list) 演算子を使用して作成されたクエリーよりもかなり遅くなる場合があります。

  • 一般に、テーブルを変更することも、サブクエリーの同じテーブルから選択することもできません。たとえば、この制限は次の形式のステートメントに適用されます。

    DELETE FROM t WHERE ... (SELECT ... FROM t ...);
    UPDATE t ... WHERE col = (SELECT ... FROM t ...);
    {INSERT|REPLACE} INTO t (SELECT ... FROM t ...);

    例外: FROM 句内の変更されたテーブルでサブクエリーを使用している場合、前述の禁止事項は適用されません。例:

    UPDATE t ... WHERE col = (SELECT * FROM (SELECT ... FROM t...) AS _t ...);

    ここでは、FROM 句内のサブクエリーの結果が一時テーブルとして格納されるので、t 内の対応する行は、t に対する更新が行われる前にすでに選択されています。

  • 行比較演算は一部のみサポートされています。

    • expr [NOT] IN subquery の場合、exprn タプル (行コンストラクタ構文を使用して指定します) にでき、サブクエリーは n タプルの行を返すことができます。したがって、許可されている構文は、具体的には row_constructor [NOT] IN table_subquery と表されます

    • expr op {ALL|ANY|SOME} subquery の場合、expr はスカラー値にする必要があり、サブクエリーはカラムサブクエリーにする必要があります。複合カラム行を返すことはできません。

    つまり、n タプルの行を返すサブクエリーの場合、次のものはサポートされています。

    (expr_1, ..., expr_n) [NOT] IN table_subquery

    ただし、次のものはサポートされていません。

    (expr_1, ..., expr_n) op {ALL|ANY|SOME} subquery

    IN の行比較がサポートされているのに、他はサポートされていない理由は、IN が、= 比較および AND 演算のシーケンスに、これを書き換えることによって実装されているためです。この方法は、ALLANYSOME には使用できません。

  • FROM 句のサブクエリーは相関サブクエリーにはできません。これらは、クエリー実行中にすべて実体化 (結果セットを生成するように評価) されるので、外部クエリーの行ごとに評価できません。MySQL 5.6.3 より前では、実体化は外部クエリーの評価の前に行われます。5.6.3 以降では、オプティマイザは、結果が必要になるまで実体化を遅らせ、これにより実体化を回避できます。セクション8.2.1.18.3「FROM 句内のサブクエリー (派生テーブル) の最適化」を参照してください。

  • MySQL は特定のサブクエリー演算子にサブクエリーの LIMIT をサポートしていません。

    mysql> SELECT * FROM t1
        ->   WHERE s1 IN (SELECT s2 FROM t2 ORDER BY s1 LIMIT 1);
    ERROR 1235 (42000): This version of MySQL doesn't yet support
     'LIMIT & IN/ALL/ANY/SOME subquery'
  • オプティマイザは、サブクエリーに対してよりも結合に対するほうが完成度が高いので、多くの場合、サブクエリーを使用するステートメントは、結合として書き換えた場合のほうが効率的に実行できます。

    IN サブクエリーを SELECT DISTINCT 結合として書き換えることができる場合には、例外が生じます。例:

    SELECT col FROM t1 WHERE id_col IN (SELECT id_col2 FROM t2 WHERE condition);

    このステートメントは次のように書き換えることができます。

    SELECT DISTINCT col FROM t1, t2 WHERE t1.id_col = t2.id_col AND condition;
  • MySQL では、サブクエリーで行をテーブルに挿入するなどのデータ変更の副作用があるストアドファンクションを参照できます。たとえば、f() が行を挿入する場合、次のクエリーはデータを変更できます。

    SELECT ... WHERE x IN (SELECT f() ...);

    この動作は、SQL 標準に対する拡張です。MySQL では、オプティマイザでの処理方法の選択に応じて、特定のクエリーの実行ごとに f() が異なる回数実行される場合があるため、これにより不確定な結果が生成される可能性があります。

    ステートメントベースまたは混合形式のレプリケーションの場合、この不確定性には、このようなクエリーが、マスターとそのスレーブで異なる結果を生成することがあります。

  • MySQL 5.6.3 より前では、FROM 句のサブクエリーは、結果を一時テーブルに実体化することにより評価され、このテーブルではインデックスが使用されません。5.6.3 以降では、クエリー実行がさらに高速になる場合は、オプティマイザは実体化されたテーブルにインデックスを作成します。セクション8.2.1.18.3「FROM 句内のサブクエリー (派生テーブル) の最適化」を参照してください。


User Comments
User comments in this section are, as the name implies, provided by MySQL users. The MySQL documentation team is not responsible for, nor do they endorse, any of the information provided here.
Sign Up Login You must be logged in to post a comment.