私は昔ながらのMySQLユーザーであり、常にサブクエリJOIN
よりも優先しています。しかし、今日では誰もがサブクエリを使用しており、私はそれが嫌いです。理由はわかりません。
何か違いがあるかどうかを自分で判断するための理論的な知識が不足しています。サブクエリはと同じくらい良いので、JOIN
心配する必要はありませんか?
私は昔ながらのMySQLユーザーであり、常にサブクエリJOIN
よりも優先しています。しかし、今日では誰もがサブクエリを使用しており、私はそれが嫌いです。理由はわかりません。
何か違いがあるかどうかを自分で判断するための理論的な知識が不足しています。サブクエリはと同じくらい良いので、JOIN
心配する必要はありませんか?
回答:
MySQLマニュアルから取得(13.2.10.11結合としてのサブクエリの書き換え):
LEFT [OUTER] JOINは、サーバーがそれをより適切に最適化できる可能性があるため、同等のサブクエリよりも高速になる可能性があります。これは、MySQLサーバーのみに固有のことではありません。
したがって、サブクエリはよりも遅くなる可能性がありますLEFT [OUTER] JOIN
が、私の意見では、その長所は読みやすさがわずかに高いということです。
Join
でsub query
は構文が異なるので、比較できない読みやすさです。SQL構文に長けている限り、どちらも読みやすさが向上します。パフォーマンスはより重要です。
サブクエリは、「Aからファクトを取得し、Bからファクトを条件とする」という形式の問題を解決するための論理的に正しい方法です。このような場合、結合を行うよりも、Bをサブクエリに固定するほうが論理的です。また、Bに対して複数の一致があるため、Aから重複したファクトを取得することに注意する必要がないため、実際的な意味でも安全です。
しかし実際には、答えは通常パフォーマンスにあります。一部のオプティマイザは、結合とサブクエリが与えられたときにレモンを吸う場合もあれば、反対にレモンを吸う場合もあり、これはオプティマイザ固有、DBMSバージョン固有、およびクエリ固有です。
歴史的に、明示的な結合は通常勝つため、結合の確立された知恵はより優れていますが、オプティマイザは常に改善されているため、まず論理的に首尾一貫した方法でクエリを記述し、パフォーマンスの制約がこれを保証する場合は再構築することを好みます。
select custid from cust join bought using (custid) where price > 500
。顧客が複数の高価なアイテムを購入した場合、ダブルアップが表示されます。この問題を解決するには、select custid from cust where exists (select * from bought where custid = cust.custid and price > 500)
。select distinct …
代わりに使用することもできますが、多くの場合、オプティマイザまたはエバリュエーターのどちらかにより多くの作業が必要になります。
ほとんどの場合、JOIN
sはサブクエリよりも高速であり、サブクエリが高速になることは非常にまれです。
JOIN
RDBMSは、クエリの方が良い実行計画を作成することができますし、それがすべてのクエリを実行し、処理を行うためにすべてのデータをロードしますサブクエリとは異なり、データが処理されるようにロードされるべきかを予測し、時間を節約することができます。
サブクエリの優れた点は、サブクエリがJOIN
s よりも読みやすいということです。そのため、ほとんどの新しいSQLの人々はそれらを好みます。それは簡単な方法です。ただし、パフォーマンスについては、JOINSの方が読みにくいものではありませんが、ほとんどの場合、JOINSの方が優れています。
select * from a where a.x = (select b.x form b where b.id = a.id)
、結合と比較して非常に短いです。これは非常に具体的な問題ですが、場合によっては数時間から数分かかることがあります。
EXPLAINを使用して、データベースがデータに対してクエリを実行する方法を確認します。この答えには「依存する」という巨大なものがあります...
PostgreSQLは、一方が他方よりも高速であると判断した場合、サブクエリを結合に、またはサブクエリへの結合を書き換えることができます。すべては、データ、インデックス、相関、データ量、クエリなどに依存します。
2010年に私はこの質問の著者に加わって強く投票しましたJOIN
が、はるかに多くの経験(特にMySQLの場合)があれば、私は次のように述べることができます。ここで複数の回答を読みました。いくつかのサブクエリはより高速ですが、十分な説明がありませんでした。私はこの(非常に)遅い回答を提供できるといいのですが:
まず、最も重要なことを言いましょう:サブクエリにはさまざまな形式があります
2番目の重要なステートメント:サイズが重要
サブクエリを使用する場合は、DBサーバーがサブクエリを実行する方法に注意する必要があります。特に、サブクエリが1回またはすべての行に対して評価される場合は! 一方、最新のDBサーバーは多くの最適化を行うことができます。場合によっては、サブクエリがクエリの最適化に役立ちますが、新しいバージョンのDBサーバーは最適化を廃止する可能性があります。
SELECT moo, (SELECT roger FROM wilco WHERE moo = me) AS bar FROM foo
からのすべての結果行に対してサブクエリが実行されることに注意してくださいfoo
。
可能であればこれを避けてください。巨大なデータセットでのクエリが大幅に遅くなる可能性があります。ただし、サブクエリが参照を持たない場合、foo
DBサーバーは静的コンテンツとして最適化でき、一度しか評価できません。
SELECT moo FROM foo WHERE bar = (SELECT roger FROM wilco WHERE moo = me)
運が良ければ、DBはこれを内部的にに最適化しJOIN
ます。そうでない場合、クエリはfoo
、select-typeのような結果だけでなく、のすべての行に対してサブクエリを実行するため、巨大なデータセットでは非常に遅くなります。
SELECT moo, bar
FROM foo
LEFT JOIN (
SELECT MIN(bar), me FROM wilco GROUP BY me
) ON moo = me
これは面白い。サブクエリJOIN
と組み合わせます。そして、ここにサブクエリの真の強みがあります。数百万の行が含まれているwilco
が、数行しか異なるデータセットを想像してくださいme
。巨大なテーブルに対して結合する代わりに、結合する小さな一時テーブルがあります。これにより、データベースのサイズによってはクエリがはるかに高速になる場合があります。CREATE TEMPORARY TABLE ...
およびを使用しても同じ効果が得られ、INSERT INTO ... SELECT ...
非常に複雑なクエリでの読みやすさが向上する可能性があります(ただし、反復可能な読み取り分離レベルでデータセットをロックできます)。
SELECT moo, bar
FROM (
SELECT moo, CONCAT(roger, wilco) AS bar
FROM foo
GROUP BY moo
HAVING bar LIKE 'SpaceQ%'
) AS temp_foo
ORDER BY bar
複数のレベルでサブクエリをネストできます。結果をグループ化または並べ替える必要がある場合、これは巨大なデータセットで役立ちます。通常、DB-Serverはこのために一時テーブルを作成しますが、場合によっては、結果セットのみでテーブル全体をソートする必要はありません。これにより、テーブルのサイズによってはパフォーマンスが大幅に向上する場合があります。
サブクエリはaに代わるものではないため、JOIN
このように使用することはできません(可能ですが)。私の控えめな意見では、サブクエリの正しい使い方はの素早い置き換えとしての使い方ですCREATE TEMPORARY TABLE ...
。適切なサブクエリは、のON
ステートメントでは達成できない方法でデータセットを削減しますJOIN
。サブクエリは、キーワードのいずれかを持っている場合GROUP BY
、またはDISTINCT
、好ましくは選択フィールドまたはステートメントに位置していない、それはパフォーマンスのAロットを向上することがあります。
Sub-queries in the Join-statement
:(1)サブクエリ自体から派生テーブルを生成するには、非常に長い時間がかかる場合があります。(2)結果の派生テーブルにはインデックスが付けられません。これら2つだけでは、SQLが大幅に遅くなる可能性があります。
10
インデックスがないため、一時テーブルのサイズをレコードに縮小できる場合でも、他のテーブルを結合するときに、一時テーブルを使用しない場合よりも9倍多くのデータレコードをクエリする可能性があります。ところで、以前はdb(MySQL)でこの問題がありましたが、私の場合、サブクエリを使用するSELECT list
方がはるかに高速でした。
EXPLAIN
最適化する前に、クエリで使用することをお勧めします。set profiling=1
一時テーブルがボトルネックになっている場合は、古いものを簡単に見ることができます。また、インデックスでさえ処理時間が必要ですが、Bツリーはレコードのクエリを最適化しますが、10レコードのテーブルは、数百万のレコードのインデックスよりもはるかに高速です。しかし、それはフィールドのサイズやタイプなどの複数の要因に依存します。
まず、最初に2つを比較するには、クエリをサブクエリと区別して、次のことを行う必要があります。
最初のクラスのクエリの場合、優れたRDBMSは結合とサブクエリを同等と見なし、同じクエリプランを生成します。
最近ではmysqlでもそれを行っています。
それでも、そうでない場合もありますが、これは結合が常に勝つという意味ではありません。mysqlでサブクエリを使用するとパフォーマンスが向上する場合がありました。(たとえば、mysqlプランナーがコストを正しく見積もることができない場合、およびプランナーがjoin-variantとsubquery-variantを同じように認識しない場合、サブクエリは特定のパスを強制することにより、結合よりも優れたパフォーマンスを発揮します)。
結論としては、どちらの方がパフォーマンスが良いかを確認したい場合は、結合とサブクエリの両方のクエリをテストする必要があります。
2番目のクラスの場合、これらのクエリは結合を使用して書き換えることができないため、比較は意味がありません。これらの場合、サブクエリは必要なタスクを実行する自然な方法であり、それらを区別しないでください。
引用された回答で強調されていないのは、特定の(使用)ケースから発生する可能性のある重複および問題のある結果の問題です。
(マルセロカントスはそれを言及していますが)
SQLに関するスタンフォード大学のLagunitaコースの例を引用します。
+------+--------+------+--------+
| sID | sName | GPA | sizeHS |
+------+--------+------+--------+
| 123 | Amy | 3.9 | 1000 |
| 234 | Bob | 3.6 | 1500 |
| 345 | Craig | 3.5 | 500 |
| 456 | Doris | 3.9 | 1000 |
| 567 | Edward | 2.9 | 2000 |
| 678 | Fay | 3.8 | 200 |
| 789 | Gary | 3.4 | 800 |
| 987 | Helen | 3.7 | 800 |
| 876 | Irene | 3.9 | 400 |
| 765 | Jay | 2.9 | 1500 |
| 654 | Amy | 3.9 | 1000 |
| 543 | Craig | 3.4 | 2000 |
+------+--------+------+--------+
(特定の大学・専攻への出願)
+------+----------+----------------+----------+
| sID | cName | major | decision |
+------+----------+----------------+----------+
| 123 | Stanford | CS | Y |
| 123 | Stanford | EE | N |
| 123 | Berkeley | CS | Y |
| 123 | Cornell | EE | Y |
| 234 | Berkeley | biology | N |
| 345 | MIT | bioengineering | Y |
| 345 | Cornell | bioengineering | N |
| 345 | Cornell | CS | Y |
| 345 | Cornell | EE | N |
| 678 | Stanford | history | Y |
| 987 | Stanford | CS | Y |
| 987 | Berkeley | CS | Y |
| 876 | Stanford | CS | N |
| 876 | MIT | biology | Y |
| 876 | MIT | marine biology | N |
| 765 | Stanford | history | Y |
| 765 | Cornell | history | N |
| 765 | Cornell | psychology | Y |
| 543 | MIT | CS | N |
+------+----------+----------------+----------+
CS
(大学に関係なく)専攻に応募した学生のGPAスコアを見つけましょう
サブクエリを使用する:
select GPA from Student where sID in (select sID from Apply where major = 'CS');
+------+
| GPA |
+------+
| 3.9 |
| 3.5 |
| 3.7 |
| 3.9 |
| 3.4 |
+------+
この結果セットの平均値は次のとおりです。
select avg(GPA) from Student where sID in (select sID from Apply where major = 'CS');
+--------------------+
| avg(GPA) |
+--------------------+
| 3.6800000000000006 |
+--------------------+
結合の使用:
select GPA from Student, Apply where Student.sID = Apply.sID and Apply.major = 'CS';
+------+
| GPA |
+------+
| 3.9 |
| 3.9 |
| 3.5 |
| 3.7 |
| 3.7 |
| 3.9 |
| 3.4 |
+------+
この結果セットの平均値:
select avg(GPA) from Student, Apply where Student.sID = Apply.sID and Apply.major = 'CS';
+-------------------+
| avg(GPA) |
+-------------------+
| 3.714285714285714 |
+-------------------+
平均値の計算で重複をカウントすることを考えると、2番目の試みがユースケースで誤解を招く結果をもたらすことは明らかです。またdistinct
、joinベースのステートメントでを使用しても、スコアの3つのオカレンスのうち1つが誤って保持されるため、問題が解消されないことも明らかです3.9
。正しいケースは、クエリ基準に一致するスコアを持つ2人の生徒が実際にいる場合、スコアの2回の発生を考慮に入れることです。3.9
パフォーマンスの問題以外に、サブクエリが最も安全な方法である場合があります。
サブクエリを含む多くのTransact-SQLステートメントは、代わりに結合として作成できます。その他の質問は、サブクエリでのみ提起できます。Transact-SQLでは、通常、サブクエリを含むステートメントと、含まない意味的に同等のバージョンの間にパフォーマンスの違いはありません。ただし、存在を確認する必要がある場合には、結合を使用するとパフォーマンスが向上します。それ以外の場合は、重複を確実に排除するために、ネストされたクエリを外部クエリの結果ごとに処理する必要があります。そのような場合、結合アプローチはより良い結果をもたらします。
だからあなたが何かのようなものが必要な場合
select * from t1 where exists select * from t2 where t2.parent=t1.id
代わりに結合を使用してください。それ以外の場合、違いはありません。
私は言います:サブクエリ用の関数を作成することはcluttterの問題を排除し、サブクエリに追加のロジックを実装することを可能にします。したがって、可能な限りサブクエリの関数を作成することをお勧めします。
コードの乱雑さは大きな問題であり、業界は何十年もの間それを回避することに取り組んできました。
NOT EXISTS
。a NOT EXISTS
はLEFT OUTER JOIN
、さまざまな理由でに勝っています:パフォーマンス、フェイルセーフ(nulable列の場合)、読みやすさ。sqlperformance.com/2012/12/t-sql-queries/left-anti-semi-join
古いMambo CMSの非常に大きなデータベースで実行します。
SELECT id, alias
FROM
mos_categories
WHERE
id IN (
SELECT
DISTINCT catid
FROM mos_content
);
0秒
SELECT
DISTINCT mos_content.catid,
mos_categories.alias
FROM
mos_content, mos_categories
WHERE
mos_content.catid = mos_categories.id;
〜3秒
EXPLAINは、同じ数の行を検査することを示していますが、1つは3秒かかり、1つはほぼ瞬時です。この話の教訓?パフォーマンスが重要な場合(そうではない場合)、複数の方法を試して、どれが最も高速かを確認してください。
そして...
SELECT
DISTINCT mos_categories.id,
mos_categories.alias
FROM
mos_content, mos_categories
WHERE
mos_content.catid = mos_categories.id;
0秒
繰り返しますが、同じ結果、同じ数の行が調査されました。私の推測では、DISTINCT mos_content.catidは、DISTINCT mos_categories.idよりも、理解するのにはるかに長い時間がかかると考えられます。
id
を付け、次のような名前を付けないようにすべきcatid
ですか?私のdbアクセスを最適化しようとすると、あなたの学習が役立つ可能性があります。
2つのケースのような私の観察によると、テーブルに100,000未満のレコードがある場合、結合は高速に動作します。
ただし、テーブルに100,000を超えるレコードがある場合は、サブクエリが最適です。
クエリの下に作成した500,000レコードのテーブルが1つあり、その結果時間は
SELECT *
FROM crv.workorder_details wd
inner join crv.workorder wr on wr.workorder_id = wd.workorder_id;
結果:13.3秒
select *
from crv.workorder_details
where workorder_id in (select workorder_id from crv.workorder)
結果:1.65秒
サブクエリは通常、単一の行をアトミック値として返すために使用されますが、INキーワードを使用して複数の行と値を比較するために使用される場合があります。これらは、ターゲットリストやWHERE句など、SQLステートメントのほぼすべての意味のある場所で許可されます。単純なサブクエリを検索条件として使用できます。たとえば、テーブルのペア間:
SELECT title FROM books WHERE author_id = (SELECT id FROM authors WHERE last_name = 'Bar' AND first_name = 'Foo');
サブクエリの結果に通常の値演算子を使用するには、1つのフィールドのみを返す必要があることに注意してください。他の値のセット内に単一の値が存在するかどうかを確認する場合は、INを使用します。
SELECT title FROM books WHERE author_id IN (SELECT id FROM authors WHERE last_name ~ '^[A-E]');
これは、結合条件がテーブルBで一致するレコードを見つけられない場合でも、テーブルAとBからのものを結合するLEFT-JOINなどとは明らかに異なります。
速度が心配な場合は、データベースを確認して適切なクエリを作成し、パフォーマンスに大きな違いがあるかどうかを確認する必要があります。
MySQLバージョン:5.5.28-0ubuntu0.12.04.2-log
また、JOINは常にMySQLのサブクエリよりも優れているという印象を受けましたが、EXPLAINが判断を下すための優れた方法です。以下は、サブクエリがJOINよりもうまく機能する例です。
これが3つのサブクエリを持つ私のクエリです:
EXPLAIN SELECT vrl.list_id,vrl.ontology_id,vrl.position,l.name AS list_name, vrlih.position AS previous_position, vrl.moved_date
FROM `vote-ranked-listory` vrl
INNER JOIN lists l ON l.list_id = vrl.list_id
INNER JOIN `vote-ranked-list-item-history` vrlih ON vrl.list_id = vrlih.list_id AND vrl.ontology_id=vrlih.ontology_id AND vrlih.type='PREVIOUS_POSITION'
INNER JOIN list_burial_state lbs ON lbs.list_id = vrl.list_id AND lbs.burial_score < 0.5
WHERE vrl.position <= 15 AND l.status='ACTIVE' AND l.is_public=1 AND vrl.ontology_id < 1000000000
AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=43) IS NULL
AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=55) IS NULL
AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=246403) IS NOT NULL
ORDER BY vrl.moved_date DESC LIMIT 200;
EXPLAINショー:
+----+--------------------+----------+--------+-----------------------------------------------------+--------------+---------+-------------------------------------------------+------+--------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+--------------------+----------+--------+-----------------------------------------------------+--------------+---------+-------------------------------------------------+------+--------------------------+
| 1 | PRIMARY | vrl | index | PRIMARY | moved_date | 8 | NULL | 200 | Using where |
| 1 | PRIMARY | l | eq_ref | PRIMARY,status,ispublic,idx_lookup,is_public_status | PRIMARY | 4 | ranker.vrl.list_id | 1 | Using where |
| 1 | PRIMARY | vrlih | eq_ref | PRIMARY | PRIMARY | 9 | ranker.vrl.list_id,ranker.vrl.ontology_id,const | 1 | Using where |
| 1 | PRIMARY | lbs | eq_ref | PRIMARY,idx_list_burial_state,burial_score | PRIMARY | 4 | ranker.vrl.list_id | 1 | Using where |
| 4 | DEPENDENT SUBQUERY | list_tag | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.l.list_id,const | 1 | Using where; Using index |
| 3 | DEPENDENT SUBQUERY | list_tag | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.l.list_id,const | 1 | Using where; Using index |
| 2 | DEPENDENT SUBQUERY | list_tag | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.l.list_id,const | 1 | Using where; Using index |
+----+--------------------+----------+--------+-----------------------------------------------------+--------------+---------+-------------------------------------------------+------+--------------------------+
JOINを使用した同じクエリは次のとおりです。
EXPLAIN SELECT vrl.list_id,vrl.ontology_id,vrl.position,l.name AS list_name, vrlih.position AS previous_position, vrl.moved_date
FROM `vote-ranked-listory` vrl
INNER JOIN lists l ON l.list_id = vrl.list_id
INNER JOIN `vote-ranked-list-item-history` vrlih ON vrl.list_id = vrlih.list_id AND vrl.ontology_id=vrlih.ontology_id AND vrlih.type='PREVIOUS_POSITION'
INNER JOIN list_burial_state lbs ON lbs.list_id = vrl.list_id AND lbs.burial_score < 0.5
LEFT JOIN list_tag lt1 ON lt1.list_id = vrl.list_id AND lt1.tag_id = 43
LEFT JOIN list_tag lt2 ON lt2.list_id = vrl.list_id AND lt2.tag_id = 55
INNER JOIN list_tag lt3 ON lt3.list_id = vrl.list_id AND lt3.tag_id = 246403
WHERE vrl.position <= 15 AND l.status='ACTIVE' AND l.is_public=1 AND vrl.ontology_id < 1000000000
AND lt1.list_id IS NULL AND lt2.tag_id IS NULL
ORDER BY vrl.moved_date DESC LIMIT 200;
そして出力は:
+----+-------------+-------+--------+-----------------------------------------------------+--------------+---------+---------------------------------------------+------+----------------------------------------------+
| id | select_type | table | type | possible_keys | key | key_len | ref | rows | Extra |
+----+-------------+-------+--------+-----------------------------------------------------+--------------+---------+---------------------------------------------+------+----------------------------------------------+
| 1 | SIMPLE | lt3 | ref | list_tag_key,list_id,tag_id | tag_id | 5 | const | 2386 | Using where; Using temporary; Using filesort |
| 1 | SIMPLE | l | eq_ref | PRIMARY,status,ispublic,idx_lookup,is_public_status | PRIMARY | 4 | ranker.lt3.list_id | 1 | Using where |
| 1 | SIMPLE | vrlih | ref | PRIMARY | PRIMARY | 4 | ranker.lt3.list_id | 103 | Using where |
| 1 | SIMPLE | vrl | ref | PRIMARY | PRIMARY | 8 | ranker.lt3.list_id,ranker.vrlih.ontology_id | 65 | Using where |
| 1 | SIMPLE | lt1 | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.lt3.list_id,const | 1 | Using where; Using index; Not exists |
| 1 | SIMPLE | lbs | eq_ref | PRIMARY,idx_list_burial_state,burial_score | PRIMARY | 4 | ranker.vrl.list_id | 1 | Using where |
| 1 | SIMPLE | lt2 | ref | list_tag_key,list_id,tag_id | list_tag_key | 9 | ranker.lt3.list_id,const | 1 | Using where; Using index |
+----+-------------+-------+--------+-----------------------------------------------------+--------------+---------+---------------------------------------------+------+----------------------------------------------+
rows
列の比較で違いがわかり、JOINを使用したクエリが使用しているUsing temporary; Using filesort
ます。
もちろん、両方のクエリを実行すると、最初のクエリは0.02秒で完了し、2番目のクエリは1分後でも完了しないため、EXPLAINはこれらのクエリを適切に説明しました。
list_tag
テーブルにINNER JOINがない場合、つまり削除した場合
AND (SELECT list_id FROM list_tag WHERE list_id=l.list_id AND tag_id=246403) IS NOT NULL
最初のクエリから、それに対応して:
INNER JOIN list_tag lt3 ON lt3.list_id = vrl.list_id AND lt3.tag_id = 246403
2番目のクエリから、EXPLAINは両方のクエリに対して同じ数の行を返し、これらのクエリはどちらも同等に高速に実行されます。
サブクエリには、オンザフライで集計関数を計算する機能があります。たとえば、本の最低価格を見つけて、この価格で販売されているすべての本を取得します。1)サブクエリの使用:
SELECT titles, price
FROM Books, Orders
WHERE price =
(SELECT MIN(price)
FROM Orders) AND (Books.ID=Orders.ID);
2)JOINの使用
SELECT MIN(price)
FROM Orders;
-----------------
2.99
SELECT titles, price
FROM Books b
INNER JOIN Orders o
ON b.ID = o.ID
WHERE o.price = 2.99;
GROUP BY
異なるテーブルを持つ複数のs:stackoverflow.com/questions/11415284/…サブクエリは厳密により一般的なようです。MySQLのman:dev.mysql.com/doc/refman/5.7/en/optimizing-subqueries.html | も参照してください。dev.mysql.com/doc/refman/5.7/en/rewriting-subqueries.html
一部の人々は、「いくつかのRDBMSを書き換えることができると言う副問合せをする参加したり参加にサブクエリ。それは1が速く、他のよりも思ったとき」が、この文は、単純な場合に、確実ではないとの複雑なクエリに適用されるサブクエリ、実際にA原因パフォーマンスの問題。
違いは、2番目の結合テーブルにプライマリテーブルよりもかなり多くのデータがある場合にのみ見られます。以下のような経験をした...
10万エントリのusersテーブルとそのメンバーシップデータ(友情)が約30万エントリありました。これは、友人とそのデータを取得するための結合ステートメントでしたが、大幅に遅延しました。しかし、メンバーシップテーブルに少量のデータしかなかった場合、問題なく機能していました。サブクエリを使用するように変更したら、問題なく動作しました。
しかし、その間、結合クエリは、プライマリテーブルよりもエントリが少ない他のテーブルで機能しています。
だから私は結合とサブクエリステートメントがうまく機能していると思います、それはデータと状況に依存します。
同じ問題について考えているだけですが、FROMの部分でサブクエリを使用しています。大きなテーブルから接続してクエリを実行する必要があります。「スレーブ」テーブルには2,800万件のレコードがありますが、結果は128しかないので、結果はビッグデータです。MAX()関数を使用しています。
最初はLEFT JOINを使用しています。それが正しい方法だと思うので、mysqlは最適化できるなどです。2回目は、テストのためだけに、JOINに対してサブ選択するように書き換えます。
LEFT JOINランタイム:1.12秒SUB-SELECTランタイム:0.06秒
ジョインよりもサブセレクトが18倍高速です!チョキト前売で。副選択はひどいように見えますが、結果...
結合を使用してクエリを高速化する場合:
「内部結合/結合」の場合は、「ON」条件で使用する代わりにwhere条件を使用しないでください。例えば:
select id,name from table1 a
join table2 b on a.name=b.name
where id='123'
Try,
select id,name from table1 a
join table2 b on a.name=b.name and a.id='123'
「左/右結合」の場合、「オン」条件では使用しないでください。左/右結合を使用すると、1つのテーブルのすべての行が取得されるため、「オン」では使用しないでください。だから、「どこ」の条件を使用してみてください