15

最近、私が管理しているデータベースで、次の形式のインデックスに遭遇しました。

CREATE INDEX [IX_Foo] ON [Foo]
( Id ASC )
INCLUDE 
( SubId )

この特定のケースでは、私が遭遇したパフォーマンスの問題 (Id と SubId の両方での低速な SELECT フィルタリング) は、SubId 列をインクルード列としてではなく、適切なインデックスに移動するだけで修正できました。

しかし、これは、一般に、それらが単にインデックス自体の一部である可能性がある場合に、含まれる列の背後にある理由をまったく理解していないと私に考えさせました。アイテムがインデックス自体に含まれていることを特に気にしなくても、単に含まれているのではなく、インデックスに列があることにはマイナス面があります。

いくつかの調査の後、インデックス付きの列に入れることができるものには多くの制限があることに気付きました (インデックスの最大幅、および「画像」のようにインデックスを作成できないいくつかの列の種類)。これらの場合、索引ページのデータに列を含める必要があることがわかります。

私が考えることができる唯一のことは、SubId に更新がある場合、列が含まれていれば行を再配置する必要がないということです (ただし、インデックスの値を変更する必要があります)。私が見逃しているものは他にありますか?

データベース内の他のインデックスを調べて、可能な場合は適切なインデックスに含まれる列をシフトすることを検討しています。これは間違いでしょうか?

私は主に MS SQL Server に興味がありますが、他の DB エンジンに関する情報も歓迎します。

4

3 に答える 3

9

これまでの答えはすべて正しく、すべてですが、カバーするインデックスから得られるものを十分に伝えていない可能性があります。

あなたの場合、テーブルFooといくつかのフィールドがあります。Idこれには、(主キーであると思います)と、SubIdある種の追加IDであるaが含まれます。

IX_Fooあなたはまた、私が今のところそこにしか持っていなかったと思うインデックスを持っていIdます。

SubIdだから今あなたはのために見つける必要がありますId=4

SELECT Id, SubId
FROM Foo
WHERE Id=4
  • SQL ServerはSELECTステートメントを調べて、使用できるかどうかを判断しますIX_Foo
  • Id=4次に、インデックス内の値を検索しますIX_Foo
  • 見つかったら、の値も必要になりSubIdます
  • 非クラスター化インデックスIX_Fooには、クラスター化キー値が含まれます
  • そのクラスタリングキー値を使用して、SQL Serverは「ブックマークルックアップ」を実行し、データ行全体が配置されている実際のデータページを検索します。
  • そのページをフェッチし、SubIdそこから値を抽出します
  • クエリを満たすためにそれらの値を返します

ここでの主なポイントは、SQL ServerがインデックスであなたId=4を見つけたら、値IX_Fooを見つけることができるように、データ行全体をフェッチするために、別のI/O操作であるブックマークルックアップを実行する必要があるということです。SubId

カバーインデックスがある場合、たとえばIX_Foo、が含まれている場合SubId、ブックマークルックアップを実行するための余分なI/Oが排除されます。インデックスで値Id=4が見つかると、IX_Foo非クラスター化インデックスのそのインデックスページには次の値も含まれます-SQL Serverは、追加の操作を行うことなくSubId、SELECTクエリで要求した2つの値を返すことができます(コストがかかる可能性があります。したがって、遅い)別のId列をフェッチするためだけにブックマークルックアップを実行します。

これがインデックスをカバーする主な利点です。ルックアップを実行しているインデックス値に加えて、1つまたは2つの追加の列のみが必要な場合は、それらの値をインデックス自体に含めることで、ブックマークのルックアップを大幅に節約できます。物事を大幅にスピードアップします。ただし、含める必要のある情報はごくわずかであり、データ行全体をすべての非クラスター化インデックスに複製しないでください。それは重要ではありません。

更新:トレードオフは次のとおりです。(Id、SubId)にインデックスがある場合、インデックス内のすべてのページに両方の列(インデックスツリー全体)があります。

INCLUDE(S​​ubId)の場合、SubIdフィールドはリーフレベルにのみ存在します。

これの意味は

  • SQL ServerはSubIdを検索および比較できません(値はインデックスツリーにありません)
  • 値はリーフレベルのみであるため、使用されるスペースが少なくなります
于 2010-03-13T09:03:59.320 に答える
7

インデックスに列を追加する理由は、インデックスで使用される列のみを必要とするクエリを実行するときに、インデックス自体からクエリを実行できるようにするためです。このようにして、テーブルに戻る時間とリソースを節約できます。これが発生した場合、インデックスはクエリのカバリングインデックスであると言います。

この追加の列を「適切なインデックス」の一部にしたくない理由は、その列で挿入または更新を行うときに、インデックスの一部を再ソートする必要が生じる可能性が高いためです。

于 2010-03-13T01:43:53.223 に答える
3

インデックスにインクルードを使用すると、それらの列を実際のツリー部分に追加することなく、インデックスをカバリング インデックスとして使用できます (つまり、クラスター化インデックスへのブックマーク ルックアップを実行する必要なく、そのインデックスのみを使用して特定のクエリを満たすことができます)。これにより、インデックスのサイズを抑えることができます。(含まれる列は、インデックスのリーフ ノードにのみ追加されます)。

于 2010-03-13T01:44:36.293 に答える