WHERE句で結合されたクエリと、実際のJOINを使用するクエリの間に重要な違いはありますか?


32

ではSQLを学びハード・ウェイ(エクササイズ6) 、作者では、以下のクエリ:

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

その後、次のように言います:

実際には、これらの種類のクエリを機能させる「結合」と呼ばれる他の方法があります。これらの概念はめちゃくちゃ混乱しているので、今のところは避けています。とりあえずこのテーブルの結合方法に固執し、これが何らかの理由で遅いか「低クラス」であることを伝えようとする人々を無視してください。

本当?なぜですか?


3
あるとは思いませんが、クエリの実行に違いがあるかどうかを確認するためにEXPLAINを試してみてください。
GrandmasterB

6
「めちゃくちゃ混乱しているから」という概念をスキップして、タイトルの「ハードウェイ」と作品の矛盾する信号を指摘したいと思います。しかし、「ハードな方法」がどうあるべきかという私の概念だけが間違っているかもしれません。しかし、再び、多分そうではありません。
マインドウィン

7
JOINは、意図(テーブルを結合する)を非常にうまく転送します。これにより、実際のフィルター用のWHERE部分が残り、読みやすくなります。(他の意味を除く)
00 00

2
著者が単純な結合を書くことに煩わされなければ、あなたはSQLを苦労して学んでいます!ThomasSがJOINを使用することで言うように、意図はより明確になり、WHERE句ははるかに単純になります。また、JOINを使用すると、SQLの基礎となる集合論がよくわかります。
ダニエルホリンレーク

1
「でも、この基本的な概念はスキップします。これはcraaazzzyyyyバナナだからです」と言いながら、何かを教えることを意図していることについて私がどう感じているかわかりません。学ぶために別のソースを探してしまうと思います。ある時点で、外部結合と相互結合を行う必要があり、それらの方法を知っている必要があります。
モーリスリーブス

回答:


23

著者のアプローチでは、外部結合を教えることははるかに困難になります。INNER JOINのON句は、他の多くのものと同じように私を驚かせたものではありませんでした。たぶん昔のやり方を学んだことがないからでしょう。私たちがそれを取り除いた理由があり、独善的ではなく、このメソッドを低クラスと呼ぶことはなかったと思います。

これは、著者が作成した非常に狭いシナリオに当てはまります。

  • ONの使用が複雑なSQLのエントリレベル
  • JOIN / INNER JOINのみを考慮し、OUTER JOINは考慮しない
  • 他の人のコードを読む必要がなく、ONの使用経験のある人が自分のコードを読んだり使用したりする必要がない孤立したコーダー。
  • 大量の複雑なクエリを必要としない:テーブル、if's、but's and or's。

教育の進行の一環として、それを分解して自然な進行を持たせる方が簡単だと思います:

Select * from table
select this, something, that from table
select this from table where that = 'this'
select this from table join anothertable on this.id = that.thisid

テーブルの結合とフィルタリングの概念は実際には同じではありません。著者が以下のような時代遅れ/非推奨のものを教えるつもりでない限り、外部結合を学ぶとき、正しい構文を学ぶことは今より多くの持ち越しを持つでしょう *= or =*


5
JOINステートメントが追加された理由は、外部結合を表現するための標準がなかったためです。そのため、各データベースベンダーには独自の「特別な」(互換性のない)構文がありました。IIRC Oracleには*==*左または右の外部結合がありました|=。これは、演算子を使用してサポートされる左外部結合のみを使用していました。
TMN

1
@TMN IIRC Oracleが使用した+=か、そうだっ=+たかもしれません。*=Transact-SQL(Sybase以降のMS-SQL)だったと思います。それでも、良い点。
デビッド

1
複雑になり始めるのは(IMHO)、内部結合と外部結合が混在している場合です。そのような状況では、WHERE句の結合を実行する「低クラス」の手法に時々陥ることを認めます。(これはシータ結合と呼ばれることを聞いたことがありますが、それが正しいかどうか
デビッド

「より大きい」または「等しい」などのIIRC演算子は、「シータ演算子」と呼ばれることもありましたが、Google検索では、計算で何らかの操作が行われます。
ウォルターミッティ

12

遅くなるかどうかは、クエリオプティマイザーと、クエリを効率化する方法によって異なります(実際に実行されるものではありません)。ただし、この引用の大きな問題は、まったく異なる動作をするさまざまな種類の結合があるという事実を完全に無視することです。例えば、言われていることは(理論的に)に対して真ですがinner joinsouter joinsleft joinsright joins)には当てはまりません。


9
+1他の種類の結合の場合。私の参加のほとんどはINNER JOINまたはLEFT OUTER JOINです。それらは「めちゃくちゃ混乱する」ことはありません。SQLはめちゃくちゃ混乱する可能性がありますが、これはその例ではありません。
mgw854

トピック外ですが、ステートメントは異なるタイプの結合または結合タイプですか?
user1451111

9

著者は、古い構文または新しい構文のいずれかを使用できる単純なケースを提示します。テーブルの結合は基本的なSQLクエリの概念であるため、結合がめちゃくちゃ混乱するという彼/彼女の声明には同意しません。したがって、多分著者は、複数のテーブルクエリの例を行うだけでなく、意見を述べるステートメントを発声する前に、JOINSがどのように機能するかを説明するのに少し時間を費やすべきでした。

新しい構文を使用する必要があります。これの主な論点は、クエリに次のものがあることです。

  • 基準を選択
  • 参加基準
  • フィルター基準

古いスタイルを使用すると、結合基準とフィルター基準が組み合わされ、より複雑な場合に混乱を招く可能性があります。

また、フィルター句の結合条件を忘れることでデカルト積を取得できます。

 person_pet.person_id = person.id

古い構文を使用します。

新しい構文を使用すると、INNER、LEFT OUTERなどが必要かどうかに重要な結合の発生方法も指定されるため、JOIN構文に関しては、IMHOが結合テーブルに不慣れな人にとって読みやすくなります。


5

クエリパーサーは、記述方法に関係なく、同等のクエリに対して同等の内部表現を生成する必要があります。著者はpre-SQL-92構文を使用しているため、「旧式」または「低クラス」と見なされる可能性があることに言及しています。内部的には、パーサーとオプティマイザーは同じクエリプランを生成する必要があります。


5

この方法でSQLを学びました。これには*=、外部結合の構文も含まれます。私にとっては、すべてのリレーションに同じ優先順位が与えられ、クエリを一連の質問として設定するのに優れた仕事をしたため、非常に直感的でした。どこから欲しい?どっちがいい?

これによりjoin構文を、それがより強く関係への思考プロセスを中断させます。そして、個人的には、テーブルとリレーションが混在しているため、コードの可読性がはるかに低くなっています。

少なくともMSSQLでは、同じ結合順序を使用すると仮定した場合、クエリのパフォーマンスに意味のある違いはありません。そうは言っても、この方法でSQLを学習(および使用)することには、明確で大きな問題が1つあります。関係の1つを忘れると、予期しないクロス積が発生します。些細でないサイズのデータ​​ベースでは、これは非常に高価です(そして、非選択者にとっては危険です!)。joinスタイル構文を使用する場合、関係を忘れるのははるかに困難です。


7
これはリレーショナルデータベースであるため、クエリにとってリレーションシップは非常に重要です。個人的には、真のフィルター(foo.x = 5)とリレーションシップ(foo.x = bar.x)を組み合わせたクエリを理解することははるかに困難です。エンジンはこれを簡単に結合に最適化できますが、人間は基本的に、セットやサブセットとは対照的に、行ごとに推論する必要があります。
アーロンノート

4

これには、パフォーマンス保守性/可読性の 2つの側面を考慮する必要があります 。

保守性/読みやすさ

あなたが投稿した元のクエリよりも良い/悪い例だと思うので、別のクエリを選択しました。

見た目が良く、読みやすいものは何ですか?

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e
inner join HumanResources.EmployeeDepartmentHistory edh
on e.BusinessEntityID = edh.BusinessEntityID
inner join HumanResources.Department d
on edh.DepartmentID = d.DepartmentID
where d.Name = 'Engineering';

または...

select
    e.LoginID,
    DepartmentName = d.Name
from HumanResources.Employee e, 
HumanResources.EmployeeDepartmentHistory edh,
HumanResources.Department d
where e.BusinessEntityID = edh.BusinessEntityID
and edh.DepartmentID = d.DepartmentID
and d.Name = 'Engineering';

個人的には、最初のものはとても読みやすいです。テーブルをINNER JOINで結合していることがわかります。つまり、後続の結合句で一致する行をプルしています(つまり、「BusinessEntityIDでEmployeeDepartmentHistoryに従業員を結合し、それらの行を含める」)。

後者の場合、コンマは私には何の意味もありません。これらのWHERE句の述語のすべてであなたが何をしているのか不思議に思います。

前者は私の脳が考えるようにもっと読む。私は毎日SQLを見て、結合のコンマを見てます。それは私の次のポイントに私を導きます...

実際には、これらの種類のクエリを「結合」と呼ばれる動作させる他の方法があります

それらはすべて結合です。コンマも結合です。作者が彼らを呼んでいないという事実は、確かに彼らの没落です....それは明らかではありません。明らかなはずです。あなたが指定したかどうか、リレーショナルデータに参加していますJOIN,

性能

これは、間違いなくRDBMSに依存します。Microsoft SQL Serverを代表してのみ話すことができます。パフォーマンスに関しては、これらは同等です。どうして知っていますか?実行後の計画をキャプチャし、これらの各ステートメントに対してSQL Serverが正確に何を行っているかを確認します。

ここに画像の説明を入力してください

上の画像では、上記の両方のクエリを使用していることを強調しました。結合の明示的な文字(JOINvs ,)のみが異なります。SQL Serverはまったく同じことを行います。

概要

コンマを使用しないでください。明示的なJOINステートメントを使用します。


WHERE句を含むバリアントが同等であることに気づくずっと前に、INNER JOINを学びました。どちらの例も非常に読みやすいように見えます。WHEREとコンマがあるものは、さらに読みやすいかもしれません。落ちてくるのは、これらの比較的単純なクエリではなく、大規模で複雑なクエリであると思います。
ロバートハーベイ

ポイントは、コンマのバリエーションがリレーショナル結合ではないと考えることはまったく正しくありません。
トーマスストリンガー

コンマを結合として誤って解釈していると思います。コンマは単にテーブルを分離するだけです。結合を作成するのはコンマではなくWHERE条件です。
ロバートハーベイ

1
述語節で起こっていることは何もありません。リレーショナルクエリの構造を誤って解釈していると思います。WHERE句なしでコンマ結合を試みましたか?まだ機能します。デカルト結合です。コンマを使用することで何が得られると思いますか?キャラクターを保存しようとしていると言ってはいけません。
トーマスストリンガー

1
あなたの意図が明確であるため、最初の方が良いと思います。あいまいさがずっと少なくなります。
ダニエルホリンレイク

4

いいえ、まったく真実ではありません。著者は混乱のために読者を設定し、標準構文と彼が好むこの古いバリアントとの間の非常に強力な構造的相違を回避するカーゴカルトプログラミングを奨励しています。特に、WHERE句が乱雑になっていると、クエリが特別な理由を理解するのが難しくなります。

彼の例は、読者がその意味の精神地図を生成するように導き、それは非常に多くの混乱を持っています。

SELECT pet.id, pet.name, pet.age, pet.dead
    FROM pet, person_pet, person
    WHERE
    pet.id = person_pet.pet_id AND
    person_pet.person_id = person.id AND
    person.first_name = "Zed";

おおよそ、上記は次のとおりです。

すべてのペット、person_pet、およびペットIDがperson_petのpet_idと一致し、そのレコードのperson_idがFIRST_NAMEが「Zed」である人のperson_idと一致する場合、ペットのID、NAME、AGE、およびDEADを取得します

そのようなメンタルマップを使用すると、読者(何らかの理由でSQLを手動で記述している人)は、おそらく1つまたは複数のテーブルを省略して、非常に簡単に間違いを犯す可能性があります。そして、そのような方法で書かれたコードの読者は、SQL作成者が何をしようとしているのかを正確に把握するために、より一生懸命働く必要があります。( "Harder"は、構文強調表示の有無にかかわらずSQLを読み取るレベルにありますが、それでも差はゼロより大きくなります。)

JOINが一般的であるのには理由があり、それは古い古典的な「懸念の分離」カナードです。具体的には、SQLクエリの場合、データの構造化方法とデータのフィルタリング方法分離する正当な理由があります

クエリが次のように簡潔に記述されている場合

SELECT pet.id, pet.name, pet.age
FROM pet
  JOIN person_pet ON pet.id = person_pet.pet_id
  JOIN person ON person.id = person_pet.person_id
WHERE 
  person.first_name = "Zed";

読者は、求められているものの構成要素をより明確に区別します。このクエリの特徴的なフィルタは、そのコンポーネントの相互関係から分離されており、各リレーションの必要なコンポーネントは、必要な場所のすぐ隣にあります。


もちろん、最新のデータベースシステムでは、2つのスタイルの間に有意な違いはありません。ただし、データベースのパフォーマンスが唯一の考慮事項である場合、SQLクエリにも空白や大文字は使用されません。


2
これを何度か聞いたことがあるので、悪魔の擁護者を演じさせてください。Learn X the Hard Wayは、技術的な深みを持つことです。SQLをよく理解している人は、2つのアプローチが生成する出力の点で同等であることを本当に知っているはずです。
ロバートハーベイ

1
私はそれを見ることができますが、著者は、それらがまともなSQLサーバーと同等のステートメントであると単に主張しているのではありません。彼らは、JOINを使用することは「混乱させる」と主張しています。これは、ダーティコードが待機するパスです。(「いいえ、LINQを使用していない、ただ手であなたのFOR文を書く。」「コンパイラは、私は、このメソッドを呼び出すかについて気にしませんので、FN1を命名しない理由はありません」)
DougM

3

Guyは古典的な間違いを犯しています。彼は特定の実装で抽象的な概念を教えようとしています。そうするとすぐに、この種の混乱に陥ります。

最初に基本的なデータベースの概念を教えてから、それらを説明する1つの方法としてSQLを示します。

左と右の結合は、あまり重要ではないと主張することができます。外側はよく古い使用することができ、参加*=および=*構文。

これで、構文は単純であるが、単純なクエリに対してのみであると主張できます。このバージョンで複雑なクエリを実行しようとするとすぐに、恐ろしい混乱に陥ることがあります。「新しい」構文は導入されていないため、複雑なクエリを実行できません。複雑なクエリを読みやすく保守可能な方法で実行できるようになっています。


3
「Learn X the Hard Way」は別の学習アプローチです。コードを書いて、後でそれを理解します。
ロバートハーベイ

7
@RobertHarveyそれは別の学習アプローチではなく、その標準的なアプローチです。車輪が外れたときにまだその場にいる場合にのみ、後で起こります。テーブルを長方形のセルの配列であると考えるSQLを書く人が多すぎて、この方法に自信を持てない。
トニーホプキンソン

2

この例は、内部JOINを使用した単純な再定式化と同等です。違いは、JOIN構文で許可される追加の可能性のみにあります。たとえば、関連する2つのテーブルの列が処理される順序を指定できます。例https://stackoverflow.com/a/1018825/259310を参照してください

受け取った知恵は、疑わしいときは、クエリを読みやすくする方法でクエリを作成することです。しかし、JOINまたはWHEREの定式化が読みやすいかどうかは個人の好みの問題のようです。そのため、両方の形式が非常に広く普及しています。


良い答えですが、クエリオプティマイザーによってはWHEREJOINステートメント内で句を使用するか、句を使用するかによって、実際にパフォーマンスに影響を与える可能性があります。私はそれが複数回起こるのを見てきました。
ロック

パフォーマンスへの影響に関する私の経験は次のとおりです。暗黙的な結合により、クエリオプティマイザーはクエリを最適化するためのオプションを増やすことができます。具体的には、クエリオプティマイザーは、開発とクエリのどちらかでクエリをチューニングできます。オプティマイザーは、パフォーマンスを低下させるチューニングにだまされる可能性があります。私の推奨事項は、明示的な結合構文を使用し、パフォーマンスが予測可能なインデックスを持つ列を結合が使用していることを確認することです。
マイケルポッター

2

SQLを学んだとき、INNER JOIN、LEFT JOINなどのフォームは存在しませんでした。他の答えがすでに述べているように、SQLのさまざまな方言は、それぞれ固有の構文を使用して外部結合を実装していました。これにより、SQLコードの移植性が損なわれました。言語を元に戻すにはいくつかの変更が必要であり、LEFT JOINなどが彼らが決めたものでした。

すべてのINNER JOINに対して、WHERE句の結合条件と同等のカンマ結合を記述できるのは事実です。古いフォームを好む状態から新しいフォームを好む状態に移行するのに時間がかかりました。どうやら、Learning SQL the Hard Wayの著者は、古い方法の方がまだ簡単だと考えています。

違いはありますか?ええ、はい、あります。1つ目は、ON句を含むINNER JOINは、古いスタイルの結合よりも明確に作成者の意図を明らかにすることです。ON句が実際には結合条件であり、他の種類の制限ではないという事実は、より明白です。これにより、INNER JOINを使用するコードは、古いスタイルよりも読みやすくなります。これは、他の誰かのコードを保守するときに重要です。

2番目の違いは、新しいスタイルにより、クエリオプティマイザーが勝者の戦略を見つけやすくなることです。これは非常に小さな効果ですが、実在します。

3番目の違いは、INNER JOIN(または単なるJOIN)を使用して学習する場合、LEFT JOINなどを簡単に学習できることです。

それ以外は、重要な違いはまったくありません。


0

セットと形式的ロジックの観点で考えるかどうかによります。

その場合、「join」キーワードを使用しないと、正式なロジックからSQLへのより単純な進行が可能になります。

しかし、99%の人のように数学の学位で正式な論理を楽しんでいない場合は、joinキーワードを習得しやすくします。SQLは、正式な論理クエリを書き留める別の方法として大学で発表されていました。...

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