サブクエリと結合


158

次のようなサブクエリの代わりに内部結合を使用するために、別の会社から継承したアプリケーションの遅いセクションをリファクタリングしました。

WHERE id IN (SELECT id FROM ...)

リファクタリングされたクエリは、約100倍速く実行されます。(〜50秒から〜0.3)改善が期待されていましたが、それがそれほど劇的だった理由を誰かが説明できますか?where句で使用される列にはすべてインデックスが付けられました。SQLはクエリをwhere句で行ごとに1回実行しますか?

更新 -結果の説明:

違いは「where id in()」クエリの2番目の部分にあります-

2   DEPENDENT SUBQUERY  submission_tags ref st_tag_id   st_tag_id   4   const   2966    Using where

vs結合された1つのインデックス付き行:

    SIMPLE  s   eq_ref  PRIMARY PRIMARY 4   newsladder_production.st.submission_id  1   Using index


2
重複ではありません。この質問は、特に印象的なパフォーマンスの違いについてです。もう1つの質問はより一般的で、各アプローチの長所と短所、そして1つのアプローチの方が人気がある理由については自由回答です。
バジルブルク

@simhumilecoそれは改善ではありません、違いはありません、それは作者が書いたものに反しています&そのようなコードスタイルの編集は不適切です。いつコードを編集する必要がありますか?
philipxy

こんにちは@philipxy、私は著者の考えに干渉するつもりはありませんでした。
simhumileco

回答:


160

「相関サブクエリ」(つまり、where条件が、含まれているクエリの行から取得した値に依存するサブクエリ)は、各行に対して1回実行されます。非相関サブクエリ(where条件が含まれているクエリから独立しているサブクエリ)は、最初に1回実行されます。SQLエンジンは、この区別を自動的に行います。

しかし、そうです、説明計画はあなたに汚い詳細を与えます。


3
これDEPENDENT SUBQUERYは「相関サブクエリ」とまったく同じことを意味することに注意してください。
ティモ

38

インデックスで結合が発生するのに対して、すべての行に対して1回サブクエリを実行しています。


5
これは本当だとは思いません。SQLエンジンは、サブクエリを1回だけ実行し、結果をリストとして使用する必要があります。
dacracot 2008

8
これは、サブクエリが何らかの方法で外部クエリと相関している(そのデータを使用している)場合、各行で実行されます。
qbeuek 2008

4
この場合はおそらく正しいですが、一般的にはそうではありません。
エイミーB

1
OP EXPLAINDEPENDENT SUBQUERY、この動作の最も明確な指標であると述べています。
ティモ



6

データセットに対してクエリが実行される前に、クエリオプティマイザーを使用して、オプティマイザーはできるだけ多くのタプル(行)を結果セットからできるだけ早く削除できるようにクエリを整理しようとします。多くの場合、サブクエリ(特に不正なクエリ)を使用すると、外部クエリの実行が開始されるまで、結果セットからタプルをプルーニングできません。

クエリを見ていないと、元のクエリの何がそれほど悪かったかを言うのは難しいですが、おそらく、オプティマイザがこれ以上改善することはできなかったのではないでしょうか。'explain'を実行すると、データを取得するためのオプティマイザメソッドが表示されます。


4

各クエリのクエリプランを確認します。

whereJoin通常、同じ実行プランを使用して実装できるため、通常、それらの間で変更することによる速度向上ありません。


3
ははは、私は3未満のSQLでクエリプランの読み取り方法がわからないため、反対投票を行っています。
エイミーB

4

オプティマイザはあまりうまくいきませんでした。通常、それらは何の違いもなく変換でき、オプティマイザはこれを行うことができます。


4

通常、その結果は、オプティマイザがサブクエリを結合として実行できることを理解できないためです。この場合、クエリしているテーブルに対してサブクエリのテーブルを結合するのではなく、テーブルの各レコードに対してサブクエリを実行します。より「エンタープライズ」なデータベースのいくつかはこれに優れていますが、それでも時々それを逃します。


4

この質問はやや一般的なものなので、一般的な答えは次のとおりです。

基本的に、MySQLにソートするための大量の行がある場合、クエリはより長くかかります。

これを行う:

各クエリ(JOINされたクエリ、次にSubqueriedクエリ)でEXPLAINを実行し、結果をここに投稿します。

MySQLによるこれらのクエリの解釈の違いを見ることは、誰にとっても学習経験になると思います。


4

whereサブクエリは、返された行ごとに1つのクエリを実行する必要があります。内部結合は1つのクエリを実行するだけです。


3

サブクエリは「フルテーブルスキャン」を実行している可能性があります。つまり、インデックスを使用せず、メインクエリからのWhereがフィルターで除外する必要があるほど多くの行を返します。

もちろん、詳細はありませんが、それが一般的な状況です。


2

サブクエリでは、各結果に対して2番目のSELECTを再実行する必要があり、通常、各実行は1行を返します。

結合を使用すると、2番目のSELECTはさらに多くの行を返しますが、実行する必要があるのは1回だけです。利点は、結果を結合できるようになり、リレーションの結合がデータベースの得意とするところです。たとえば、おそらくオプティマイザは、インデックスをより有効に活用する方法を見つけることができます。


2

IN句ほどサブクエリではありませんが、結合は少なくともOracleのSQLエンジンの基礎であり、非常に高速に実行されます。


1
本来本質的に悪いことではありません。
Shawn

2

リファレンスマニュアルからの引用(14.2.10.11結合としてのサブクエリの書き換え):

LEFT [OUTER] JOINは、サーバーがそれをより適切に最適化できる可能性があるため、同等のサブクエリよりも高速である可能性があります。これは、MySQLサーバーのみに固有のものではありません。

したがって、サブクエリはLEFT [OUTER] JOINSよりも遅くなることがあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.