SQLサーバーでMerge結合をテストしています。私にはINNER JOIN
があり、オプティマイザにMERGE JOIN
を実行させる:
ID
は主キーですID
が主キーですこれらのテーブルには他のインデックスはありません
select * from [dbo].[Personal] as P inner join [dbo].[Abteilung] as A
on P.[ID]= A.[Personal_ID] OPTION (MERGE JOIN)
次に、オプティマイザーはこのプランを使用してクエリを実行します。
オプティマイザがindex seek
ではなくTable Scan
を使用するように強制したい
この目的を達成するために私がしたこと:
ID
、Personal_ID
のTable Abteilungでグループ化インデックスを定義します。クエリを実行すると、実行プランは次のように変更されます。ここでは、クラスター化インデックスのスキャンを行っていますが、クラスター化インデックスのシークは行っていません
FORCESEEK
ヒントの使用。このヒントを使用している場合、クエリを実行するとエラーが発生します。このクエリでヒントが定義されているため、クエリプロセッサはクエリプランを作成できませんでした。ヒントを指定せず、SET FORCEPLANを使用せずにクエリを再送信します。
クエリにwhere句を追加すると、クエリは次のようになります。
select * from [dbo].[Personal] as P inner join [dbo].[Abteilung] as A
on P.[ID]= A.[Personal_ID] where A.[Personal_ID]=2
OPTION (MERGE JOIN)
私の質問:
クエリを変更して、クラスター化インデックスシークを最終行に表示するにはどうすればよいですか?
クラスタ化インデックスシークを取得するには、フィルタをサポートするクラスタ化インデックスが必要です(たとえば、先頭のキーはID
ではなくPersonal_ID
である必要があります)。
フィルターをサポートするPersonal_ID
の先行列を持つインデックスがない場合、シークを強制することはできません。
これは、これがテーブルに対して実行した唯一のクエリでない限り、既存のクラスター化インデックスを変更する必要があることを意味するものではありません。
また、Personal_ID
をキー列として非クラスター化インデックスを作成することもできますが、SELECT *
(本当に両方のテーブルのすべての列が必要ですか?)、とにかくクラスタ化インデックスから残りの列をフェッチする必要があります。 いくつかの行 返された、ある時点でシーク(まあ、シークに偽装した範囲スキャンに相当するもの)+ルックアップは通常のスキャンよりもコストがかかります。
なぜここでシークが必要だと思いますか?クエリが返す行の数、行の幅、およびかかる時間はどれくらいですか?これは単なる教育的なものですか、それともシークは常にスキャンよりもパフォーマンスが良いという前提の下にありますか? (そうではありません。)
いくつかの有用な読み物:
テストを作成しないと、特にSELECT *を使用してすべてのテーブル列を取得する場合を除いて、シーク述語がないとインデックスをシークすることは不可能だと思います。
シークしたいインデックスの一部であるインデックス列でフィルターをかけ、さらにこのインデックスでカバーされている列のみを取得しようとします。
ドキュメントでは、Merge joinは通常、スキャンするか、後でソートすることを説明しています。読む: https://technet.Microsoft.com/en-us/library/ms190967(v = sql.105).aspx