別の会社から継承したアプリケーションの遅いセクションをリファクタリングして、次のようなサブクエリではなく内部結合を使用しました。
WHERE id IN (SELECT id FROM ...)
リファクタリングされたクエリは約100倍高速に実行されます。(〜50秒から〜0.3)改善を期待していましたが、なぜそれがそれほど劇的だったかを説明できますか? where句で使用される列はすべてインデックス化されていました。 SQLは、行または何かごとにwhere句でクエリを実行しますか?
更新-結果の説明:
違いは、「where id in()」クエリの2番目の部分にあります-
2 DEPENDENT SUBQUERY submission_tags ref st_tag_id st_tag_id 4 const 2966 Using where
対1インデックス付き行と結合:
SIMPLE s eq_ref PRIMARY PRIMARY 4 newsladder_production.st.submission_id 1 Using index
「相関サブクエリ」(つまり、where条件が含まれるクエリの行から取得した値に依存するサブクエリ)は、行ごとに1回実行されます。非相関サブクエリ(where条件が含まれるクエリから独立しているサブクエリ)は、最初に1回実行されます。 SQLエンジンは、この区別を自動的に行います。
しかし、ええ、explain-planで詳細はわかりません。
サブクエリ行ごとに1回を実行しているのに対し、結合はインデックスで行われます。
MySQL 6.0でサブクエリが評価される の例を次に示します。
新しいオプティマイザーは、この種のサブクエリを結合に変換します。
各バージョンで説明計画を実行すると、その理由がわかります。
クエリがデータセットに対して実行される前に、クエリオプティマイザーを使用して、オプティマイザーは、可能な限り迅速に結果セットからできるだけ多くのタプル(行)を削除できるようにクエリを編成しようとします。多くの場合、サブクエリ(特に悪いクエリ)を使用すると、外部クエリが実行を開始するまで、結果セットからタプルを削除できません。
クエリが表示されないため、オリジナルのどこが悪いのかを言うのは難しいですが、オプティマイザーがこれ以上改善できないと思います。 「explain」を実行すると、データを取得するオプティマイザーメソッドが表示されます。
この質問はやや一般的なので、一般的な答えは次のとおりです。
基本的に、MySQLにソートする行が大量にあると、クエリに時間がかかります。
これを行う:
各クエリ(JOINされたクエリ、次にサブクエリされたクエリ)でEXPLAINを実行し、結果をここに投稿します。
MySQLのこれらのクエリの解釈の違いを見ることは、誰にとっても学習体験になると思います。
Whereサブクエリは、返された行ごとに1つのクエリを実行する必要があります。内部結合では、1つのクエリを実行するだけです。
各クエリのクエリプランを確認します。
Where inおよびJoinは通常同じ実行プランを使用して実装されているため、通常それらの間の変更による速度向上はゼロです。
オプティマイザーはあまり良い仕事をしていませんでした。通常、それらは違いなく変換でき、オプティマイザーはこれを行うことができます。
通常、オプティマイザーの結果は、サブクエリを結合として実行できると判断できない場合です。この場合、サブクエリ内のテーブルをクエリ対象のテーブルに対して結合するのではなく、テーブル内の各レコードに対してサブクエリを実行します。いくつかの「エンタープライズ」データベースはこれで優れていますが、それでも時々見逃します。
サブクエリは、おそらく「全表スキャン」を実行していました。つまり、インデックスを使用せず、メインクエリのWhereで除外する必要がある行が多すぎます。
もちろん詳細はありませんが、それはよくある状況です。
リファレンスマニュアルから引用( 14.2.10.11サブクエリを結合として書き換え ):
LEFT [OUTER] JOINは、サーバーがより適切に最適化できる可能性があるため、同等のサブクエリよりも速くなる可能性があります。これは、MySQL Serverだけに固有のものではありません。
したがって、サブクエリはLEFT [OUTER] JOINSよりも遅くなる可能性があります。
サブクエリでは、各結果に対して2番目のSELECTを再実行する必要があり、通常、各実行は1行を返します。
結合では、2番目のSELECTはより多くの行を返しますが、実行する必要があるのは1回だけです。利点は、結果に参加できるようになったことです。関係の参加は、データベースが得意とするものです。たとえば、オプティマイザーは、インデックスをより有効に活用する方法をすぐに見つけることができます。
IN句ほどサブクエリではありませんが、結合は少なくともOracleのSQLエンジンの基盤であり、非常に高速に実行されます。