web-dev-qa-db-ja.com

JOINキーワードを使用するかどうか

次のSQLクエリは同じです。

SELECT column1, column2
FROM table1, table2
WHERE table1.id = table2.id;

SELECT column1, column2
FROM table1 JOIN table2 
ON table1.id = table2.id;

そして、確かに、これまでに試したすべてのDBMSで同じクエリプランが得られます。

しかし、私は時々、どちらかが他より確実に優れているという意見を読んだり聞いたりします。当然、これらの主張は説明によって裏付けられることはありません。

私が作業している場所では、2番目のバージョンは他の開発者の大多数に支持されているようで、そのため、驚きを最小限に抑えるためにそのスタイルを採用する傾向があります。しかし、私の心の中で、私は本当に最初のものを本当に考えています(それが私が最初にそれを学んだ方法なので).

これらの形式の1つは他の形式よりも客観的に優れていますか?そうでない場合、どちらを使用する理由は何ですか?

2番目の形式の方が良いことがわかりました。それは私が学んだ方法だからかもしれないと私は認めますが、私には1つの具体的な理由があります-懸念の分離。テーブルを結合するために使用しているフィールドをwhere句に入れると、クエリの理解が困難になる可能性があります。

たとえば、次のクエリを見てください。

select *
from table1, table2, table3, table4
where table1.id = table2.id
and table2.id = table3.id
and table3.id = table4.id
and table1.column1 = 'Value 1'

上記のクエリには、テーブル結合条件と実際のビジネスロジック条件がすべて1つのスペースに結合されています。大きなクエリでは、これを理解するのは非常に難しい場合があります。

ただし、次のコードを使用してください。

select *
from table1 join table2 on table1.id = table2.id
join table3 on table2.id = table3.id
join table4 on table3.id = table4.id
where table1.column1 = 'Value 1'

この場合、テーブルとの関係やそれらの関係はすべてfrom句に分離されますが、クエリ制限の実際のビジネスロジックはwhere句にあります。これは、特に大規模なクエリの場合、はるかに理解しやすいと思います。

62
Dustin Wilhelmi

結合構文は、1992年に古いコンマ構文を置き換えました。現在、コンマ構文を使用してコードを記述する理由はありません。何も得られず、明示的な構文ではない、いくつかの問題が発生します。

そもそも複雑なクエリを取得する場合、where条件が欠落しているため、偶発的なクロス結合が非常に簡単に発生します。これは、明示的な結合構文を使用すると、構文エラーが発生するため、発生を防止できるものです。

クロスジョインを意図している場合、明示的なジョイン構文はそれを明確にしますが、暗黙的な構文では、メンテナンスをしている誰かがwhere句を追加するのを忘れていると想定する場合があります。

次に、暗黙の構文を使用する少なくとも一部のデータベースで問題となる、左と右の結合の問題があります。これらはSQL Serverでは推奨されておらず、実際には古いバージョンでも実際には正しい結果を返しません。外部結合を必要とするクエリには、SQL Serverの暗黙の構文を含めないでください。

さらに、ここや他のサイトで、暗黙の結合と明示的な結合を混在させると(たとえば、左結合を追加するときに)間違った結果が発生するという質問を見たので、それらを混在させるのは得策ではありません。

最後に、暗黙的な結合を使用する多くの人は、実際には結合を理解していません。これは、データベースを効率的にクエリするために必要な重要な理解です。

40
HLGEM

ハ。 PostgreSQL のドキュメントを見て、たまたま自分の質問に対する可能な答えを見つけました。このページの説明を要約すると、結果のクエリは同じですが、オプティマイザが考慮しなければならないplansの数は、結合の数とともに指数関数的に増加します。

このような結合が約6回行われると、その数は非常に多くなり、クエリを計画するのに時間がかかる可能性があります。10回程度になると、オプティマイザは計画の徹底的な検索から確率的検索に切り替わり、最適な計画に到達しない可能性があります。 。

実行時パラメーターを設定することにより、明示的に言及された内部結合とクロス結合を暗黙的結合とは異なる方法で処理し、それらを計画の先頭に強制し、他のオプションを探さないようにプランナーに指示できます。

注目すべきことに、デフォルトの動作はどちらの場合も同じであり、代替プランを取得するには、異なる結果を得るためにdbmsの内部と問題のテーブルの特殊性の知識が必要です。

さて、それはそれの集合論の見解です:

コンマを使用して2つ(またはそれ以上)のテーブル名を区切る場合、意図しているのはデカルト積です。 「左」テーブルのすべての行は、右テーブルの行と「一致」します(連結されます)。

ここで、where句に何かを書き込むと、この「連結」に条件を設定して、どの行をどの行に「連結」するかを指示するようなものです。

これは実際には行を "結合"しているため、より読みやすい構文を提供するのに役立つ結合キーワードであり、いくつかの一般的な値で結合したいということを理解しやすくなっています。 @Dustinが上記で明確にしたものと同様です。

現在、すべてのDBMSはスマートです。つまり、最初にデカルト積を計算してからデータを除外する(非常に無駄な)のではなく、クエリ構造に基づいて計算します。私が考えることができる唯一のことは、あなたがそれを「参加」するように頼むとき、それは参加アクティビティを明示的にするようなものであり、おそらくコードをより速く実行するのに役立ちます(どれくらいですか?カンマで区切られたケースでは、最適な戦略を「予測」するのにしばらく時間がかかります。私は間違っているかもしれませんが、私はそれをどのようにコード化するかについて教育を受けた推測をしています...

8
PhD

その場合は、JOINステートメントを使用する方が一般に良いと思います。

将来、ステートメントをINNER JOINからOUTER JOINに変更する必要がある状況が発生した場合は、2番目のステートメントを使用する方がはるかに簡単です。

5
Britt Wescott

どのRDBMSも、実行に関しては同じものにします。読みやすく表現力があるかどうかにかかっています。

次のように、JOINを使用して、結合の一致と実際の選択が明確になるようにします。

select name, deptname
from people p, departments d
where p.deptid = d.id and p.is_temp = 'Y'

vs.

select name, deptname
from people p
    inner join departments d on p.deptid = d.id
where p.is_temp = 'Y'

後者の場合は、どちらが結合条件で、どちらが選択基準であるかがすぐにわかります。

3
Andy Lester

私はかつて一度だけ2つの異なる最適化セットの結果を見たことがあります。メモリが機能する場合、それは非常に複雑なクエリのms-sql2kにありました。その1つの例では、* =で使用された古い形式は、パフォーマンスが約4倍速くなりました。マイクロソフトの技術担当者を含め、誰もその理由を説明できませんでした。 MSの人たちはそれを間違いだと言った。二度と見たことがありません。

ほとんどのRDBMSは十分なデカルト座標系を実行しないほど賢いので、私がそれを使用しないと考えることができる最大の理由は(減価償却されていることを除いて)、30歳から35歳未満のほとんどの人はこれまで見たことがないということです以前は古いフォームであり、遭遇するとひどく失われます。

1
Bill