web-dev-qa-db-ja.com

ANSI JOINクエリと非ANSI JOINクエリのパフォーマンスは異なりますか?

T-SQLストアドプロシージャの約7000行にビジネスロジックがあり、そのほとんどに次のJOIN構文があります。

SELECT A.A, B.B, C.C
FROM aaa AS A, bbb AS B, ccc AS C
WHERE
    A.B = B.ID
AND B.C = C.ID
AND C.ID = @param

このようなクエリを次のように置き換えると、パフォーマンスが向上しますか?

SELECT A.A, B.B, C.C
FROM aaa AS A
JOIN bbb AS B
   ON A.B = B.ID
JOIN ccc AS C
   ON B.C = C.ID
   AND C.ID = @param

それとも同じですか?

55
abatishchev

2番目のクエリはANSI-92 SQL構文であり、最初のクエリはjoin句を組み込んでいない古いSQL構文であることを除いて、2つのクエリは同じです。確認することもできますが、まったく同じ内部クエリプランを作成する必要があります。

いくつかの理由からANSI-92構文を使用する必要があります

  • JOIN句を使用すると、リレーションシップロジックがフィルターロジック(WHERE)から分離されるため、より簡潔で理解しやすくなります。
  • この特定のクエリとは関係ありませんが、古い外部結合構文(+を使用)があいまいであり、クエリの結果が実装に依存する、またはクエリをまったく解決できない状況がいくつかあります。これらはANSI-92では発生しません
  • ほとんどの開発者とdbaは最近ANSI-92を使用するため、この方法をお勧めします。標準に従う必要があります。確かに、最新のクエリツールはすべてANSI-92を生成します。
  • @gbnが指摘したように、偶発的なクロス結合を避ける傾向があります。

私自身はANSI-92にしばらく抵抗しました。古い構文には概念的な利点がわずかにあり、使用されるすべてのテーブルの一括デカルト結合としてSQLを考えやすく、その後にフィルタリング操作が続くためです。 SQLクエリの実行内容を把握するため。しかし、私は数年前に時代に合わせて移動する必要があると決め、比較的短い調整期間の後、今では強く好むようになりました。これは主に上記の最初の理由によるものです。 ANSI-92構文から逸脱する、またはオプションを使用しない唯一の場所は、暗黙的に危険な自然結合です。

75
Cruachan

2番目の構造は、SQLコミュニティでは「固定結合構文」として知られています。最初の構成AFAIKには広く受け入れられている名前がないため、「古いスタイル」の内部結合構文と呼びましょう。

通常の引数は次のようになります。

「伝統的」構文の長所:述語は、クエリを一般的にする任意の順序でWHERE句で物理的にグループ化され、特にn項の関係は読みやすく、理解しやすい(ON句は述部を広げることができるため、視覚的な距離で1つのテーブルまたは列の外観を探す必要があります)。

「従来の」構文の短所:「結合」述部の1つを省略しても解析エラーはなく、結果はデカルト積(CROSS JOIN(挿入された構文では)およびそのようなエラーは、検出とデバッグが難しい場合があります。また、 'join'述語と 'filtering'述語はWHERE句で物理的に一緒にグループ化されるため、互いに混同される可能性があります。

4
onedaywhen

OK、彼らは同じことを実行します。同意しました。多くの人とは異なり、私は古い慣習を使用しています。 SQL-92が「理解しやすい」ことは議論の余地があります。プログラミング言語を40年間プッシュするために書いた(gulp)私は、「読みやすい」が最初に、他の慣習の前に、「視力」で始まることを知っています(ここでの用語の誤用ですが、私が使用できる最高のフレーズです)。 SQLを読むとき、最初に気にするのは、どのテーブルが関係し、どのテーブル(ほとんど)が粒度を定義するかです。次に、データに関連する制約を考慮し、次に属性を選択します。 SQL-92はこれらのアイデアをほとんど分離しますが、非常に多くのノイズワードがあり、心の目でこれらを解釈して対処する必要があり、SQLの読み取りが遅くなります。

SELECT Mgt.attrib_a   AS attrib_a
      ,Sta.attrib_b   AS attrib_b
      ,Stb.attrib_c   AS attrib_c
FROM   Main_Grain_Table  Mgt
      ,Surrounding_TabA  Sta
      ,Surrounding_tabB  Stb
WHERE  Mgt.sta_join_col  = Sta.sta_join_col
AND    Mgt.stb_join_col  = Stb.stb_join_col
AND    Mgt.bus_logic_col = 'TIGHT'

視力!新しい属性のカンマを前に配置しますコードのコメント化も容易にします関数とキーワードに特定のケースを使用しますテーブルに特定のケースを使用します属性に特定のケースを使用します垂直に演算子と操作を並べますFROMの最初のテーブルを作成しますデータの粒度を表すWHEREの最初のテーブルを結合制約にし、特定の厳しい制約を下に浮かせます。データベース内のすべてのテーブルに3文字のエイリアスを選択し、テーブルを参照するすべてのエイリアスを使用します。そのエイリアスは、そのテーブルの(多くの)インデックスのプレフィックスとしても使用する必要があります。 1 1/2ダースの6、右?多分。ただし、ANSI-92の規則を使用している場合でも(私が持っているように、今後もそうするように)視力の原則、垂直方向のアライメントを使用して、見たい場所に心の目をそらし、簡単に物事を避けます(特にノイズワード)する必要はありません。

4
TwoEdgedSword

両方を実行し、クエリプランを確認します。それらはべき等しい。

3
sisve

2つのクエリareは等しい-最初は非ANSI JOIN構文を使用し、2番目はANSI JOIN構文です。 ANSI JOIN構文に従うことをお勧めします。

はい、LEFT OUTER JOIN(これはANSI JOIN構文でもあります)は、結合先のテーブルに一致するレコードが含まれていない可能性がある場合に使用するものです。

参照: SQL Serverの条件付き結合

3
OMG Ponies

私の考えでは、FROM句は、SELECT句が機能するために行で必要な列を決定する場所です。これは、計算に必要な値を同じ行にもたらすビジネスルールが表現される場所です。ビジネスルールは、請求書を持つ顧客である場合があり、その結果、責任のある顧客を含む請求書の行ができます。また、クライアントと同じ郵便番号の会場である可能性があり、その結果、互いに近い会場とクライアントのリストが作成されます。

結果セットの行の中心性を計算する場所です。結局、RDBMSのリストのメタファーが表示されます。各リストはトピック(エンティティ)を持ち、各行はエンティティのインスタンスです。行の中心性が理解されると、結果セットのエンティティが理解されます。

FROM句で概念的に行が定義された後に概念的に実行されるWHERE句は、SELECT句が機能するために不要な(または必要な行を含む)行をカリングします。

結合ロジックはFROM句とWHERE句の両方で表現できるため、また複雑なロジックを分割して征服するために句が存在するため、FROM句の列に値を含む結合ロジックを配置することを選択します。列内の値の一致によってサポートされるルール。

つまり、次のようなWHERE句は書きません。

 WHERE Column1 = Column2

これを次のようにFROM句に入れます。

 ON Column1 = Column2

同様に、郵便番号を特定の郵便番号と比較するなど、列を外部値(列に含まれる場合も含まれない場合もある値)と比較する場合、基本的に私は欲しいだけだと言っているので、それをWHERE句に入れますこのような行。

すなわち、私はこのようなFROM句を書きません:

 ON PostCode = '1234'

これを次のようなWHERE句に入れます。

 WHERE PostCode = '1234'
1
John

ANSI構文では、適切な句(ONまたはWHERE)に述語を配置することも、隣接するテーブル参照に対するON句のアフィニティも強制しません。開発者はこのような混乱を自由に書くことができます

SELECT
   C.FullName,
   C.CustomerCode,
   O.OrderDate,
   O.OrderTotal,
   OD.ExtendedShippingNotes
FROM
   Customer C
   CROSS JOIN Order O
   INNER JOIN OrderDetail OD
      ON C.CustomerID = O.CustomerID
      AND C.CustomerStatus = 'Preferred'
      AND O.OrderTotal > 1000.0
WHERE
   O.OrderID = OD.OrderID;

「ANSI-92を生成する」クエリツールと言えば、生成されたため、ここでコメントします。

SELECT 1
   FROM DEPARTMENTS C
        JOIN EMPLOYEES A
             JOIN JOBS B
     ON C.DEPARTMENT_ID = A.DEPARTMENT_ID
     ON A.JOB_ID = B.JOB_ID

従来の"restrict-project-cartesian product"をエスケープする唯一の構文は外部結合です。この操作は連想的ではないため(それ自体と通常の結合の両方で)より複雑です。少なくとも、外部結合を使用してクエリを慎重に括弧で囲む必要があります。ただし、これはエキゾチックな操作です。頻繁に使用する場合は、リレーショナルデータベースクラスを使用することをお勧めします。

0
Tegiri Nenashi