2012-03-29 11 views
12

私のgoogle-fuとso-fuは私にここで失敗しているので、私はよく尋ねるかもしれません。TSQL - テーブルを結合する正しい順序は何ですか?

私はそれらに複数の結合を持つ多くのクエリを持っています。

私は、1つのクエリの中で、ヘッダー/アイテム/詳細をまとめて、これらのレコードのさまざまな情報を調べています。

私が参加するとき、私は物事をどのように関連づけているかの順番で保管しようとします。例:Myヘッダーには2つのルックアップテーブルがあるため、アイテムテーブルに参加する前にそれらのテーブルに参加します。

これは間違いありませんか?

ルックアップテーブルの前に大きなテーブルに参加する方が良いですか?またはその逆?

小さなテーブルに参加するときにヒントを使用し、openrowsetsに参加するときにmergeヒントを使用する必要がありますか?

私はその答えは「それに依存する」と確信していますが、効果的かつ効率的に参加するための一般的なガイドラインが非常に役に立ちます。ありがとう!

+0

ほとんどの場合、結合のタイプ(マージ/ループ/ハッシュ)を指定する必要はありません。もしあなたがそうしているのであれば、おそらく結合ヒントのバンドエイドの代わりに解決すべき根本的な問題があるでしょう。 –

+2

あなたが何をしているのかよく分からず、クエリ実行計画を理解していない限り、決してクエリヒントを使用しないでください。 – JotaBe

答えて

12

編集:あなたの質問(およびKirk Woll's)のコメントに基づいて、order of your joins is aesthetic, and does not directly impact the resulting execution planを理解する必要があります。クエリオプティマイザは最も効率的な順序で結合を実行し、必要なヒントなしに大部分の時間に適切な結合操作を使用します。

あなたの結合順序の美しさは少し主観的ですが、私はあなたのテーブルを論理的に意味のある順序で結合すると言っています... @HeaderIdで始めると、そのテーブルで開始し、その後、子供たちのテーブルにJOIN

FROM 
    Header h 
    JOIN Items i ON h.HeaderId = i.HeaderId 
    JOIN Details d ON i.ItemId = d.ItemId 
WHERE 
    h.HeaderId = @HeaderId 

しかし、あなたが@DetailIdでクエリを開始した場合、私は逆の順序で参加します。

FROM 
    Details d 
    JOIN Items i ON d.ItemId = i.ItemId 
    JOIN Header h ON i.HeaderId = h.HeaderId 
WHERE 
    d.DetailId = @DetailId 

しかし、それは主観的で個人的な好みです。

OUTER JOINを含めると、それほど主観的になりません... RIGHT OUTER JOINを避けるためにクエリを構造化し、その代わりにLEFT OUTER JOINを使用してください。

デフォルトでは結合ヒントを使用しないでください。実際にはほとんど使用しません。クエリオプティマイザは、最適な実行計画を選択する非常に良い仕事をします。私は計画を改善するために参加ヒントを提供する必要があった単一のインスタンスに遭遇しました...それは、その時点でクエリが実行されていたサーバーを大幅に助けましたが、データベースが別のサーバーに移行されたとき、私の参加のヒントは、クエリのパフォーマンスを破壊した。繰り返しますが、通常、参加ヒントを提供することは悪い考えです。

+1

おそらく、OPは結合順序が実行計画と無関係であり、純粋に美的であることに気付かないのでしょうか? –

+0

@KirkWollそれは私が見落とした非常に良い点です...私は私の答えでそれを明らかにするでしょう。 –

+0

@カーク、それは私が求めている理由です。順序はまったく関係ありませんか? – IronicMuffin

0

オーダーは大きく審美的ですが、混乱を避けるために、テーブルの順序とON条件の用語の両方の規則を持つと便利です。

クエリヒントは例外的なケースのみであり、使用する必要がある状況(通常並行処理の問題を軽減するためにパフォーマンスを犠牲にすること)がある場合がありますが、問題を解決するためのより堅牢な方法を常に見つけようとする必要があります。

CREATE TABLE A (
    id int IDENTITY PRIMARY KEY, 
    name varchar 
); 

CREATE TABLE B (
    id int IDENTITY PRIMARY KEY, 
    a_id int FOREIGN KEY REFERENCES A (id), 
    name varchar 
); 

SELECT * 
FROM A 
INNER LOOP JOIN B on A.id = B.a_id; 

SELECT * 
FROM B 
INNER LOOP JOIN A on A.id = B.a_id; 

第1の選択2回の索引スキャンを行い、第二スキャンとシークを行います

[1] 私は順序は問題ないものの場合を知っています。これは、ヒントを避けるもう一つの理由です。

関連する問題