web-dev-qa-db-ja.com

インデックスの選択性

非クラスター化インデックスをいつ適用するかの一般的な選択性ルールはありますか?

私たちはビット列にインデックスを作成しないことを知っています、50/50。 "50/50分布の行は、パフォーマンスの向上がほとんどない可能性があります" SQL Serverのインデックスビットフィールド

では、インデックスを適用する前に、SQL Serverでクエリをどのように選択する必要がありますか? SQL Serverガイドラインに一般的なルールはありますか?カラム内の平均選択性分布は25%ですか? 10%の選択性?

この記事は約31%と述べていますか? インデックスはどのように選択する必要がありますか?

3
user129291

インデックスを作成する列を決定するときにのみ、列の選択性を考慮して、インデックスが実行できること、およびそれらが一般的に何のために役立つかをかなり無視します。

たとえば、信じられないほど選択的である-一意である-が、決して使用されないID列またはGUID列があるとします。その場合、誰が気にしますか?クエリが影響しない列にインデックスを付けるのはなぜですか?

選択性の低いインデックスは、BIT列であっても、インデックスの有用な部分または有用な部分を作成できます。いくつかのシナリオでは、大規模なテーブルの非常に非選択的な列は、それらを並べ替える、またはグループ化する必要があるときに、インデックス付けからかなりの利益を得ることができます。

結合

次のクエリを見てください。

_SELECT COUNT(*) AS records
FROM dbo.Users AS u
JOIN dbo.Posts AS p
ON u.Id = p.OwnerUserId;
_

OwnerUserIdに役立つインデックスがない場合、これはハッシュ結合を使用した計画です-これは波及します-しかし、それは重要なことです。

NUTS

役立つインデックス-CREATE INDEX ix_yourmom ON dbo.Posts (OwnerUserId);-を使用すると、計画が変更されます。

NUTS

アグリゲート

同様に、グループ化操作は、インデックス付けの恩恵を受けることができます。

_SELECT   p.OwnerUserId, COUNT(*) AS records
FROM     dbo.Posts AS p
GROUP BY p.OwnerUserId;
_

インデックスなし:

NUTS

インデックス付き:

NUTS

ソート

データの並べ替えは、インデックスが役立つクエリの別の固定点になる可能性があります。

インデックスなし:

NUTS

私たちのインデックスで:

NUTS

ブロッキング

インデックスは、パイルアップのブロックを回避するのにも役立ちます。

この更新を実行しようとすると、次のようになります。

_UPDATE p
SET p.Score += 100
FROM dbo.Posts AS p
WHERE p.OwnerUserId = 22656;
_

そして、この選択を同時に実行します:

_SELECT *
FROM   dbo.Posts AS p
WHERE  p.OwnerUserId = 8;
_

それらは最終的にブロックされます:

NUTS

インデックスを配置すると、選択はブロックされることなく即座に完了します。 SQL Serverには、必要なデータに効率的にアクセスする方法があります。

(提供されている式Kumarを使用して)疑問に思っている場合は、OwnerUserId列の選択度は_0.0701539878296839478_です。

まとめる

列の選択性に基づいて、盲目的に列にインデックスを付けないでください。ワークロードの効率的な実行に役立つインデックスを設計します。より選択的な列を先行キー列として使用することは、通常、等価述語を検索する場合には良い考えですが、範囲を検索する場合にはあまり役に立ちません。

6
Erik Darling

選択性の計算式:

Table1のCol1の選択性を計算する必要があるとします。

_Declare @distinctcount int,@Totoalrows int
Select @distinctcount =count(distinct col1) from table1

select @Totoalrows =count(*) from table1

So Selectivity=@distinctcount /cast(@Totoalrows as decimal(5,2))
_

理想的な_Selectivity =1_つまり、一意のキーです。したがって、選択性は1に非常に近いはずです。

50/50のビット列にインデックスを配置しないことはわかっています。 "50/50分布の行。パフォーマンスの向上はほとんどありません。"

ビット列だけではあまり選択的ではありませんが、ビット列を_composite index_に配置してパフォーマンスを向上させることができます。

または、_Filtered index_のビット列を使用してパフォーマンスを向上させることができます。

この記事は約31%と述べていますか?

記事を注意深く読んでください。この記事は、選択性のほかに、クエリ中に読み取られるデータページの数も重要であると述べています。

両方のID列がインデックスとして含まれている2つのテーブルは、Ideal Selectiveと見なされます。

テーブルmanyrowsでは、すべてのint列が占めるデータページが少なくなっています。読み取られるデータページが少ないため、0.16%の選択性で十分です。

char(4000)として1列のfewrowsを含むテーブルの場合、多くのデータページが含まれます。したがって、多くのデータページが読み取られるため、選択性は31%です。

オプティマイザが多くのデータページにわたってデータを読み取る必要がある場合、オプティマイザはシークよりもスキャンを決定する可能性があることを忘れないでください。つまり、インデックスの選択性は無視されます。

3
KumarHarsh

あなたが参照しているのは、SQL Serverオプティマイザがインデックスシークやキールックアップではなくテーブルスキャンを実行することを決定する「転換点」です。

注意すべき点がいくつかあります。転換点は明らかに非クラスター化インデックスにのみ影響し(クラスター化インデックスを使用する場合はキー検索を行う必要がないため)、転換点は非クラスター化インデックスにも影響しません。 -クラスター化インデックスがカバーしています(選択したすべての列がキー列にあるか、インデックスの含まれている列にあります)。

つまり、行数はではなく行全体の30%です。固定値ではありません。

行数は、ページ数の25%から33%パーセントの間にあるため、ページごとに1行がない限り、行のパーセンテージははるかに小さくなります。

The Tipping Point Query Answers のKimberly Trippの例を参照してください

  • テーブルに500,000ページがある場合、25%= 125,000および33%= 166,000になります。したがって、125,000〜166,000 ROWSのどこかでクエリがチップします。それをパーセンテージに変換すると、125,000/1million = 12.5%、166,000/1million = 16.6%になります。したがって、テーブルに500,000ページ(および100万行)がある場合、12.5%未満のデータを返すクエリは、非クラスター化インデックスを使用してデータを検索し、16.6%を超えるクエリはテーブルを使用する可能性が高いスキャン。

  • テーブルに10,000ページある場合、25%= 2,500および33%= 3,333です。したがって、2,500〜3,333 ROWSのどこかでクエリがチップします。これを2,500/1ミリオン= .25%および3,333/1ミリオン= .33%に変換します(1%でもありません)。したがって、テーブルに10,000ページ(および100万行)しかない場合、データの1%の4分の1未満を返すクエリは、非クラスター化インデックスを使用してデータを検索し、1/3パーセントを超えるクエリは可能性が高いです。テーブルスキャンを使用する。

  • テーブルに50,000ページある場合、25%= 12,500および33%= 16,666です。したがって、12,500〜16,666 ROWSのどこかでクエリがチップします。それを12,500/1ミリオン= 1.25%および16,666/1ミリオン= 1.66%(2%未満)のパーセンテージに変換します。したがって、テーブルに50,000ページ(および100万行)がある場合、データの1.25%未満を返すクエリは非クラスター化インデックスを使用してデータを検索し、1.66%を超えるクエリはテーブルスキャンを使用する可能性が高くなります。

さて、あなたの質問に答えるために、インデックスが使用される前にそれはどのように選択すべきですか?

行のサイズとページ数に応じて、非常に選択的になる可能性があります。インデックスが使用されていることを確認したい場合は、インデックスでカバーする必要があります。