Documentation Home
MySQL 5.6 リファレンスマニュアル
Download this Manual
EPUB - 7.5Mb
HTML Download (TGZ) - 7.2Mb
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
Sign Up Login You must be logged in to post a comment.