web-dev-qa-db-ja.com

EXISTSとINを使用したサブクエリ-MySQL

以下の2つのクエリはサブクエリです。両方とも同じであり、どちらも私にとってはうまく機能します。しかし問題は、方法1のクエリの実行に約10秒かかり、方法2のクエリの実行に1秒未満かかることです。

メソッド1のクエリをメソッド2に変換できましたが、クエリで何が起こっているのか理解できません。私は自分でそれを理解しようとしています。以下の2つのクエリの違いは何ですか?また、パフォーマンスはどのように向上しますか?その背後にあるロジックは何ですか?

私はこれらの高度な技術に慣れていない。誰かが私を助けてくれることを願っています。 docs を読んだとすると、手がかりが得られません。

方法1:

SELECT
   *       
FROM
   tracker       
WHERE
   reservation_id IN (
      SELECT
         reservation_id                                 
      FROM
         tracker                                 
      GROUP  BY
         reservation_id                                 
      HAVING
         (
            method = 1                                          
            AND type = 0                                          
            AND Count(*) > 1 
         )                                         
         OR (
            method = 1                                              
            AND type = 1                                              
            AND Count(*) > 1 
         )                                         
         OR (
            method = 2                                              
            AND type = 2                                              
            AND Count(*) > 0 
         )                                         
         OR (
            method = 3                                              
            AND type = 0                                              
            AND Count(*) > 0 
         )                                         
         OR (
            method = 3                                              
            AND type = 1                                              
            AND Count(*) > 1 
         )                                         
         OR (
            method = 3                                              
            AND type = 3                                              
            AND Count(*) > 0 
         )
   )

方法2:

SELECT
   *                                
FROM
   `tracker` t                                
WHERE
   EXISTS (
      SELECT
         reservation_id                                              
      FROM
         `tracker` t3                                              
      WHERE
         t3.reservation_id = t.reservation_id                                              
      GROUP BY
         reservation_id                                              
      HAVING
         (
            METHOD = 1 
            AND TYPE = 0 
            AND COUNT(*) > 1
         ) 
         OR                                                     
         (
            METHOD = 1 
            AND TYPE = 1 
            AND COUNT(*) > 1
         ) 
         OR                                                    
         (
            METHOD = 2 
            AND TYPE = 2 
            AND COUNT(*) > 0
         ) 
         OR                                                     
         (
            METHOD = 3 
            AND TYPE = 0 
            AND COUNT(*) > 0
         ) 
         OR                                                     
         (
            METHOD = 3 
            AND TYPE = 1 
            AND COUNT(*) > 1
         ) 
         OR                                                     
         (
            METHOD = 3 
            AND TYPE = 3 
            AND COUNT(*) > 0
         )                                             
   )
20
Techie

_Explain Plan_ は、なぜExistsを使用する必要があるのか​​を示しているはずです。通常、質問はExists vs Count(*)になります。 Existsは高速です。どうして?

  • NULLによって存在する課題に関して:subqueryがNullを返す場合、INの場合、クエリ全体はNullになります。そのため、同様に処理する必要があります。しかし、Existを使用すると、それは単なるfalseです。対処がはるかに簡単です。単にINNullとは何も比較できませんが、Existsは比較できます。

  • 例えばExists (Select * from yourtable where bla = 'blabla');真/偽の瞬間ヒットが1つ見つかった/一致した

  • この場合、IN sortはCount(*)の位置を取り、選択する[〜#〜] all [〜#〜]すべての値を比較しているため、WHEREに基づいて行を一致させます。

しかし、これも忘れないでください:

  • EXISTSは、INに対して高速で実行されます。サブクエリの結果が非常に大きい場合。
  • INEXISTSよりも先になります。サブクエリの結果が非常に小さい場合。

詳細については、参照:

48
bonCodigo

方法2は、EXISTS演算子を使用しているため高速です。ここで、I MySQLは結果をロードしません。 docs リンクでも述べたように、SELECT句にあるものはすべて省略します。条件に一致する最初の値のみをチェックし、見つかったら条件TRUEを設定し、さらに処理を進めます。

一方、方法1にはIN演算子があり、すべての可能な値をロードしてから一致します。条件はTRUEに設定されますが、完全一致が見つかった場合にのみ時間がかかります。

したがって、方法2は高速です。

それが役に立てば幸い...

3
jsist

[〜#〜] exists [〜#〜]演算子は、trueまたはfalseを返すブール演算子です。 EXISTS演算子は、「exist」条件をテストするために、 subquery でよく使用されます。

SELECT 
    select_list
FROM
    a_table
WHERE
    [NOT] EXISTS(subquery);

サブクエリが行を返す場合、[〜#〜] exists [〜#〜]演算子はtrueを返し、そうでない場合はfalseを返します。

さらに、[〜#〜] exists [〜#〜]演算子は、一致する行を見つけるとすぐにそれ以降の処理を終了します。この特性のため、[〜#〜] exists [〜#〜]演算子を使用して、場合によってはクエリのパフォーマンスを向上させることができます。

[〜#〜] not [〜#〜]演算子は、[〜#〜] exists [〜 #〜]演算子。つまり、NOT EXISTSは、サブクエリが行を返さない場合はtrueを返し、そうでない場合はfalseを返します。

SELECT *SELECT columnSELECT a_constant、またはサブクエリ内の何か。 MySQLは[〜#〜] select [〜#〜]に表示されるselect_listを無視するため、結果は同じです。句。

その理由は、[〜#〜] exists [〜#〜]演算子が「少なくとも見つかった」という原則に基づいて機能するためです。 trueを返し、一致する行が少なくとも1つ見つかるとテーブルのスキャンを停止します。

一方、[〜#〜] in [〜#〜]演算子をサブクエリと組み合わせる場合、MySQLは最初にサブクエリを処理し、次に、サブクエリの結果を使用して、クエリ全体を処理します。

一般的な経験則として、サブクエリに大量のデータが含まれる場合、[〜#〜] exists [〜#〜]演算子はよりよい性能。

ただし、[〜#〜] in [〜#〜]演算子を使用するクエリは、サブクエリから返される結果セットが非常に大きい場合、より高速に実行されます。小さい。

詳細な説明と例: MySQL EXISTS-mysqltutorial.org

1
k.t

2番目のメソッドは、「WHERE t3.reservation_id = t.reservation_id」のようになっているため高速です。最初のケースでは、サブクエリはテーブルを完全にスキャンして情報を確認する必要があります。ただし、2oメソッドでは、サブクエリは探しているものを正確に認識しており、サブクエリが見つかると、その条件をチェックします。

0
medina