明示的SQL結合と暗黙的SQL結合


399

明示的な内部結合と暗黙的な内部結合に効率の違いはありますか?例えば:

SELECT * FROM
table a INNER JOIN table b
ON a.id = b.id;

SELECT a.*, b.*
FROM table a, table b
WHERE a.id = b.id;

11
良い質問。なぜ明示的な結合が使用されるのか、私は興味があります。それなしですべてのクエリを実行することは不可能ですか?
Andrew

6
EXPLAINキーワードを使用して両方のクエリの違いを確認します
。JOIN

@andrew私の質問は、暗黙の結合が「ハック」の形式であるかどうかでした(「結合を使用せずに、複数のテーブルを含むクエリですか?それはハックではないですか?」)
bobobobo

3
それらは異なり、暗黙的な結合はnull値を処理するときに時々驚かされます。明示的な結合を使用し、「何も変更されていない」ときに発生するバグを回避します。
BlackTigerX

1
違いはありません。,あるCROSS JOIN緩いバインディング&でINNER JOINあるCROSS JOINONのようなWHEREが、タイトバインディング。実行に重要なのは、DBMSがクエリを最適化する方法です。
philipxy 2017

回答:


132

パフォーマンスに関しては、それらはまったく同じです(少なくともSQL Serverでは)。

PS:IMPLICIT OUTER JOIN構文はSQL Server 2005以降廃止されていることに注意してください。(IMPLICIT INNER JOIN質問で使用されている構文は引き続きサポートされています)

「古いスタイル」のJOIN構文の廃止:部分的なもののみ


4
@lomaxxは、単に明確さのために、あなたは指定することができ廃止されて、当該2の構文?
J Wynia 2008

8
サポートドキュメントを提供できますか?これは複数のレベルで間違って聞こえます。
NotMe 2009年

21
SQL標準をどのように非推奨にしますか?
デビッドクローショー09/09/30

7
@david Crenshaw、暗黙の結合はもはや標準ではなく、18年も経っていません。
HLGEM 2010年

11
「内部」または「クロス」のさまざまな種類のいわゆる「暗黙の結合」は、標準に残っています。SQL Serverは、これまで標準ではなかった「古いスタイル」の外部結合構文(*=およびand =*)を非推奨にしています。
2011

129

個人的には、テーブルが結合されていること、およびテーブルがどのように結合されているかを明確にするため、結合構文を好みます。8つの異なるテーブルから選択し、場所に多くのフィルタリングがある場合に、より大きなSQLクエリを比較してみてください。結合構文を使用することにより、テーブルが結合されている部分と、行をフィルタリングしている部分を分離します。


4
私は完全に同意しますが、これは一種の話題外です。OPは効率について尋ねました。
villasv 2017年

56

MySQL 5.1.51では、両方のクエリに同じ実行プランがあります。

mysql> explain select * from table1 a inner join table2 b on a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.02 sec)

mysql> explain select * from table1 a, table2 b where a.pid = b.pid;
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
| id | select_type | table | type | possible_keys | key  | key_len | ref          | rows | Extra |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
|  1 | SIMPLE      | b     | ALL  | PRIMARY       | NULL | NULL    | NULL         |  986 |       |
|  1 | SIMPLE      | a     | ref  | pid           | pid  | 4       | schema.b.pid |   70 |       |
+----+-------------+-------+------+---------------+------+---------+--------------+------+-------+
2 rows in set (0.00 sec)

table1166208行あります。table2約1000行あります。

これは非常に単純なケースです。クエリオプティマイザーが混乱しないこと、およびより複雑なケースで異なるプランが生成されることを決して証明しません。


これは受け入れられる答えになるはずです。これは正しいです。計画は同じです(または、より大きなステートメントに近い)が、レコードの量が大幅に増えるため、パフォーマンスに違いが生じます。
SovietFrontier

37

2番目の構文には、クロス結合の不要な可能性があります。対応するWHERE句なしでFROM部分にテーブルを追加できます。これは有害と見なされます。


from句のテーブル名がwhere句で使用されているテーブルから生成された場合はどうなりますか?
Jus12

あなたは明示的にはうまくとしてJOIN構文をしてクロス結合行うことができます。(stackoverflow.com/a/44438026/929164を)あなたは、おそらくそれは、あまり厳格なユーザー・エラーに、より傾向があることを意味しました。
Daniel Dubovski

15

あなたが与えた最初の答えは、ANSI結合構文として知られているものを使用しています。もう1つは有効で、どのリレーショナルデータベースでも機能します。

ANSIの結合構文を使用する必要があることは、Gromに同意します。彼らが言ったように、主な理由は明確にするためです。多くの述語を含むwhere句ではなく、一部の結合テーブルやその他のANSI結合構文で返される行を制限しているため、テーブルの結合に使用されている条件と、結果。


5

パフォーマンスに関しては、これらはまったく同じですが(少なくともSQL Serverでは)、この結合構文は非推奨であり、そのままではsql server2005ではサポートされていないことに注意してください。

非推奨の* =および= *演算子と「外部結合」との比較を考えていると思います。

与えられた2つの形式をテストしたところ、SQL Server 2008データベースで正しく動作します。私の場合、それらは同じ実行プランを生み出しましたが、これが常に真実であるとは確信を持って言えませんでした。


5

@lomaxx:明確にするために、上記の構文は両方ともSQL Serv 2005でサポートされていると確信しています。ただし、以下の構文はサポートされていません

select a.*, b.*  
from table a, table b  
where a.id *= b.id;

具体的には、外部結合(* =)はサポートされていません。


2
率直に言って、SQL Server 2000でもそれを使用しません。* =構文は、しばしば間違った答えを出します。これらをクロス結合として解釈する場合があります。
HLGEM 2009年

2

一部のデータベース(特にOracle)では、結合の順序がクエリのパフォーマンスに大きな違いをもたらす可能性があります(テーブルが3つ以上ある場合)。1つのアプリケーションでは、文字通り2桁の差があった場合があります。内部結合構文を使用すると、これを制御できます-適切なヒント構文を使用する場合。

使用しているデータベースを指定しませんでしたが、SQL ServerまたはMySQLで実際に違いがない場所である可能性があります。


1
リー、暗黙の結合でもヒントを使用できます。
SquareCog 2008年

1
Oracleでは、結合順序が意味のある方法で実行プランに影響を与えることは非常にまれです。説明については、Jonathan Lewisによるこの記事を参照してください。
Jon Heller

1

Leigh Caldwellが述べたように、クエリオプティマイザーは、機能的に同じSQLステートメントのように見えるものに基づいて、異なるクエリプランを生成できます。詳細については、次の2つのブログ投稿をご覧ください。

Oracleオプティマイザチームからの投稿

「構造化データ」ブログからの別の投稿

これが面白いと思います。


マイク、彼らが話している違いは、明示的な結合を指定する場合、フィルターではなく結合する結合条件を指定する必要があることを確認する必要があることです。意味的に正しいクエリの場合、execプランは同じであることに注意してください。
SquareCog 2008年

1

パフォーマンスに関しては、違いはありません。明示的な結合構文は、from句内のテーブル間の関係を明確に定義し、where句を散らかさないため、私にはわかりやすく見えます。


0

基本的に、2つの違いは、1つは古い方法で記述され、もう1つは現代的な方法で記述されていることです。個人的には、内側、左側、外側、右側の定義を使用した最新のスクリプトの方が説明がわかりやすく、コードが読みやすくなるので、私は好みです。

内部結合を処理する場合、読みやすさには実質的な違いはありませんが、左と右の結合を処理する場合、古いメソッドのように次のような結果になるため、複雑になる可能性があります。

SELECT * 
FROM table a, table b
WHERE a.id = b.id (+);

上記は、以下とは対照的に、左結合の古い方法です。

SELECT * 
FROM table a 
LEFT JOIN table b ON a.id = b.id;

視覚的にわかるように、スクリプトを作成する最新の方法により、クエリが読みやすくなります。(ちなみに、正しい結合については同じことが言え、外部結合についてはもう少し複雑です)。

ボイラープレートに戻ると、SQLコンパイラは、クエリを同じように処理するため、クエリの記述方法に違いはありません。私は、多くの人がそれを書いているOracleデータベースで、高齢者と若い人の両方が混在するのを見てきました。繰り返しになりますが、それは、スクリプトがどの程度読みやすくなるかと、開発しているチームに要約されます。


-1

私の経験では、特にMicrosoft SQL製品を使用している場合、cross-join-with-a-where-clause構文を使用すると、多くの場合、脳に損傷のある実行計画が作成されます。たとえば、SQL Serverがテーブルの行数を推定する方法は、ひどく恐ろしいものです。内部結合構文を使用すると、クエリの実行方法をある程度制御できます。したがって、実用的な観点から見ると、現在のデータベーステクノロジーの非アクティブな性質を考えると、内部結合を使用する必要があります。


5
これの証拠はありますか?受け入れられた答えはそうではないので。
cimmanon
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.