web-dev-qa-db-ja.com

SQLまたはMySQLでJOINキーワードを使用しない結合に何か問題がありますか?

データベースクエリを書き始めたとき、私はまだJOINキーワードを知りませんでした。当然、私はすでに知っていることを拡張して、次のようなクエリを書きました。

SELECT a.someRow, b.someRow 
FROM tableA AS a, tableB AS b 
WHERE a.ID=b.ID AND b.ID= $someVar

これが内部結合と同じであることがわかったので、コード内でこれらすべてのクエリを見つけて、それらを書き直す必要があるかどうかを自問します。それらに何か臭いがありますか、それとも問題ありませんか?


編集:

私の回答の要約:このクエリに問題はありませんが、キーワードを使用すると、コードが読みやすく、保守しやすくなります。

私の結論:古いクエリは変更しませんが、今後は文体を修正してキーワードを使用します。

あなたの答えをありがとう!

42
markus

WHEREのみを使用して結合をフィルタリングすると、一部の一般的なシナリオでは非常に非効率になる可能性があります。例えば:

SELECT * FROM people p, companies c 
    WHERE p.companyID = c.id AND p.firstName = 'Daniel'

ほとんどのデータベースは、このクエリを文字通り実行します。最初にpeopleテーブルとcompaniesテーブルの デカルト積 を取得し、次に一致するcompanyIDフィールドとidフィールドを持つものによるフィルタリング。完全に拘束されていない製品は、メモリ内以外には存在せず、ほんの一瞬ですが、その計算には時間がかかります。

より良いアプローチは、必要に応じてJOINsで制約をグループ化することです。これは主観的に読みやすいだけでなく、はるかに効率的です。したがって:

SELECT * FROM people p JOIN companies c ON p.companyID = c.id
    WHERE p.firstName = 'Daniel'

少し長くなりますが、データベースはON句を調べて、すべてで開始するのではなく、完全に制約されたJOINを直接計算するために使用できます。 そして制限します。これは計算が速く(特に大きなデータセットや多数のテーブルの結合がある場合)、必要なメモリが少なくて済みます。

「commaJOIN」構文を使用するすべてのクエリを変更します。私の意見では、その存在の唯一の目的は簡潔さです。パフォーマンスへの影響を考えると、これが説得力のある理由ではないと思います。

37
Daniel Spiewak

より冗長なINNER JOIN, LEFT OUTER JOIN, RIGHT OUTER JOIN, FULL OUTER JOINは、結合用のANSI SQL/92構文からのものです。私にとって、この冗長性により、開発者/ DBAは、結合の意図が何であるかをより明確に理解できます。

10

SQL Serverには、チェックするクエリプランが常にあり、テキスト出力は次のように行うことができます。

SET SHOWPLAN_ALL ON
GO

DECLARE @TABLE_A TABLE
(
    ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    Data VARCHAR(10) NOT NULL
)
INSERT INTO @TABLE_A
SELECT 'ABC' UNION 
SELECT 'DEF' UNION
SELECT 'GHI' UNION
SELECT 'JKL' 

DECLARE @TABLE_B TABLE
(
    ID INT IDENTITY(1,1) NOT NULL PRIMARY KEY,
    Data VARCHAR(10) NOT NULL
)
INSERT INTO @TABLE_B
SELECT 'ABC' UNION 
SELECT 'DEF' UNION
SELECT 'GHI' UNION
SELECT 'JKL' 

SELECT A.Data, B.Data
FROM
    @TABLE_A AS A, @TABLE_B AS B
WHERE
    A.ID = B.ID

SELECT A.Data, B.Data
FROM
    @TABLE_A AS A
    INNER JOIN @TABLE_B AS B ON A.ID = B.ID

ここで、テーブル変数が作成する計画を省略しますが、両方のクエリの計画は同じです。

 SELECT A.Data, B.Data  FROM   @TABLE_A AS A, @TABLE_B AS B  WHERE   A.ID = B.ID
  |--Nested Loops(Inner Join, OUTER REFERENCES:([A].[ID]))
       |--Clustered Index Scan(OBJECT:(@TABLE_A AS [A]))
       |--Clustered Index Seek(OBJECT:(@TABLE_B AS [B]), SEEK:([B].[ID]=@TABLE_A.[ID] as [A].[ID]) ORDERED FORWARD)
 SELECT A.Data, B.Data  FROM   @TABLE_A AS A   INNER JOIN @TABLE_B AS B ON A.ID = B.ID
  |--Nested Loops(Inner Join, OUTER REFERENCES:([A].[ID]))
       |--Clustered Index Scan(OBJECT:(@TABLE_A AS [A]))
       |--Clustered Index Seek(OBJECT:(@TABLE_B AS [B]), SEEK:([B].[ID]=@TABLE_A.[ID] as [A].[ID]) ORDERED FORWARD)

だから、短い答え-あなたがそれらを維持するたびにそれらを読むことを試みるのに長い時間を費やさない限り、書き直す必要はありませんか?

6
Meff

それは構文の選択です。結合条件を結合とグループ化することを好むため、INNERJOIN構文を使用します

SELECT a.someRow, b.someRow
FROM tableA AS a
INNER JOIN tableB AS b
  ON a.ID = b.ID
WHERE b.ID = ?

(?プレースホルダーであること)

5
Powerlord

古い結合構文で考慮すべきもう1つのことは、on句がないため、誤ってカルテシオン結合を取得するのが非常に簡単であるということです。 Distinctキーワードがクエリに含まれていて、古いスタイルの結合を使用している場合は、それをANSI標準結合に変換して、それでも個別が必要かどうかを確認します。この方法で偶発的なカーテション結合を修正する場合は、結合フィールドと結合フィールドを指定するように書き直すことで、パフォーマンスを大幅に向上させることができます。

4
HLGEM

一般に:

JOINキーワードを使用して、主キーと外部キーをリンク(つまり「結合」)します。

WHERE句を使用して、結果セットを関心のあるレコードのみに制限します。

4
ilitirit

発生する可能性のある問題の1つは、同じクエリで古い「コンマスタイル」結合とSQL-92結合を混在させようとした場合です。たとえば、1つの内部結合と別の外部結合が必要な場合などです。

SELECT *
FROM table1 AS a, table2 AS b
 LEFT OUTER JOIN table3 AS c ON a.column1 = c.column1
WHERE a.column2 = b.column2;

問題は、最近のSQL標準では、JOINはコンマ結合の前に評価されるとされていることです。そのため、ON句が評価されているため、相関名がまだ定義されていないため、ON句で「a」を参照するとエラーが発生します。これは非常に紛らわしいエラーです。

解決策は、2つのスタイルの結合を混在させないことです。古いコードで引き続きコンマスタイルを使用できますが、新しいクエリを作成する場合は、すべての結合をSQL-92スタイルに変換してください。

SELECT *
FROM table1 AS a
 INNER JOIN table2 AS b ON a.column2 = b.column2
 LEFT OUTER JOIN table3 AS c ON a.column1 = c.column1;
4
Bill Karwin

あなたの例の構文には何も問題はありません。 'INNER JOIN'構文は、一般に 'ANSI'構文と呼ばれ、例に示されているスタイルの後にあります。結合のタイプ/方向/構成要素を明確にするために存在しますが、一般的に機能的にはあなたが持っているものと違いはありません。

「ANSI」結合のサポートはデータベースごとのプラットフォームですが、最近では多かれ少なかれ普遍的です。

補足として、「ANSI」構文の1つの追加は、「FULLOUTERJOIN」または「FULLJOIN」でした。

お役に立てれば。

4
Jared

暗黙的な結合は避けます。クエリが非常に大きい場合、コードの解読が困難になります

明示的な結合と適切なフォーマットにより、コメントを必要とせずにコードが読みやすく、理解しやすくなります。

3
Cade Roux

また、この方法で内部結合を行っているのか、外部結合を行っているのかによっても異なります。たとえば、WHERE句(= *および* =)の外部結合のMS SQL Server構文は、OUTER JOIN構文とは異なる結果をもたらす可能性があり、サポートされなくなりました( http://msdn.Microsoft.com SQL Server 2005の/en-us/library/ms178653(SQL.90).aspx )。

2
Sean Carpenter