以下の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
)
)
_Explain Plan
_ は、なぜExists
を使用する必要があるのかを示しているはずです。通常、質問はExists vs Count(*)
になります。 Exists
は高速です。どうして?
NULLによって存在する課題に関して:subqueryがNull
を返す場合、INの場合、クエリ全体はNull
になります。そのため、同様に処理する必要があります。しかし、Exist
を使用すると、それは単なるfalse
です。対処がはるかに簡単です。単にIN
はNull
とは何も比較できませんが、Exists
は比較できます。
例えばExists (Select * from yourtable where bla = 'blabla');
真/偽の瞬間ヒットが1つ見つかった/一致した。
この場合、IN
sortはCount(*)
の位置を取り、選択する[〜#〜] all [〜#〜]すべての値を比較しているため、WHERE
に基づいて行を一致させます。
しかし、これも忘れないでください:
EXISTS
は、IN
に対して高速で実行されます。サブクエリの結果が非常に大きい場合。IN
はEXISTS
よりも先になります。サブクエリの結果が非常に小さい場合。詳細については、参照:
方法2は、EXISTS
演算子を使用しているため高速です。ここで、I MySQL
は結果をロードしません。 docs リンクでも述べたように、SELECT
句にあるものはすべて省略します。条件に一致する最初の値のみをチェックし、見つかったら条件TRUE
を設定し、さらに処理を進めます。
一方、方法1にはIN
演算子があり、すべての可能な値をロードしてから一致します。条件はTRUE
に設定されますが、完全一致が見つかった場合にのみ時間がかかります。
したがって、方法2は高速です。
それが役に立てば幸い...
[〜#〜] 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 column、SELECT a_constant、またはサブクエリ内の何か。 MySQLは[〜#〜] select [〜#〜]に表示されるselect_listを無視するため、結果は同じです。句。
その理由は、[〜#〜] exists [〜#〜]演算子が「少なくとも見つかった」という原則に基づいて機能するためです。 trueを返し、一致する行が少なくとも1つ見つかるとテーブルのスキャンを停止します。
一方、[〜#〜] in [〜#〜]演算子をサブクエリと組み合わせる場合、MySQLは最初にサブクエリを処理し、次に、サブクエリの結果を使用して、クエリ全体を処理します。
一般的な経験則として、サブクエリに大量のデータが含まれる場合、[〜#〜] exists [〜#〜]演算子はよりよい性能。
ただし、[〜#〜] in [〜#〜]演算子を使用するクエリは、サブクエリから返される結果セットが非常に大きい場合、より高速に実行されます。小さい。
詳細な説明と例: MySQL EXISTS-mysqltutorial.org
2番目のメソッドは、「WHERE t3.reservation_id = t.reservation_id」のようになっているため高速です。最初のケースでは、サブクエリはテーブルを完全にスキャンして情報を確認する必要があります。ただし、2oメソッドでは、サブクエリは探しているものを正確に認識しており、サブクエリが見つかると、その条件をチェックします。