web-dev-qa-db-ja.com

含まれる列を持つインデックス、違いは何ですか?

これら2つのインデックスの違いを本当に理解したことはありませんが、違いが何であるかを説明してもらえますか(パフォーマンス面、dbでのインデックス構造の見え方、ストレージ面など)?

私はこの質問が広範であることを理解しています。これについてはご容赦ください。私はそれをどのようにスコープダウンするのか本当に知りません。おそらく、皆さんがあなたのノウハウを説明し始めたら、私は正しい方向にポインターを取得して、質問をより狭くすることができますか?

含まれるインデックス

CREATE NONCLUSTERED INDEX IX_Address_PostalCode  
ON Person.Address (PostalCode) 
INCLUDE (AddressLine1, AddressLine2, City, StateProvinceID); 

「標準」インデックス

CREATE NONCLUSTERED INDEX IX_Address_PostalCode  
ON Person.Address (PostalCode, AddressLine1, AddressLine2, City, StateProvinceID);
18
dadde

インデックスの内部ストレージはBツリー構造を使用し、「インデックスページ」(ルートページとすべての中間ページ)と「インデックスデータページ」(リーフページのみ)で構成されます。

「インデックスデータページ」と、実際のデータのほとんどの列を格納する「データページ」(クラスター化インデックスのリーフページ)を混同しないでください。

  • インデックスページにのみインデックス列が格納されます。
  • INCLUDEセクションにいくつかの列を配置することにより、各ページに格納されるインデックスキーごとのデータが少なくなります。
  • インデックスキーを保持するために必要なページ数が少なくなります。 (これらの頻繁に使用されるページをより長くメモリに簡単にキャッシュできるようにします。
  • また、ツリー内のレベルがおそらく少ない。 (このような場合、すべてのツリーレベルトラバーサルが別のディスクアクセスであるため、パフォーマンス上のメリットははるかに大きくなる可能性があります。

インデックスを使用する場合、インデックスキーを使用して、インデックスページ間を移動して正しいインデックスデータページに移動します。

  • インデックスにINCLUDE列がある場合、クエリで必要な場合、そのデータはすぐに利用できます。
  • クエリでインデックスキーまたはINCLUDE列のいずれでも使用できない列が必要な場合、クラスター化インデックス(またはクラスター化インデックスが定義されていない場合はヒープ)の正しい行に対して追加の "ブックマークルックアップ"が必要です。

あなたの混乱のいくつかに対処することを願っています。

  • クエリのインデックスとフィルターのキーがselectiveで十分でない場合、インデックスは無視されます(INCLUDE列の内容に関係なく)。
  • 作成するすべてのインデックスには、INSERTおよびUPDATEステートメントのオーバーヘッドがあります。 「より大きい」インデックスの場合。 (INCLUDE列にも大きく適用されます。)
  • したがって、理論的には、アクセスパスのすべての順列に一致するinclude列を持つ多数の大きなインデックスを作成できますが、非常に非生産的です。

INCLUDE列が機能として追加される前に注意する価値があります。

  • インデックスのキーを拡張して、インデックス/フィルターで不要な列を含めることは、「トリック」を調整する一般的なインデックスでした。 (カバーリングインデックスとして知られています。)
  • これらの列は、通常、出力列で、または他のテーブルへの結合の参照列として必要でした。
  • これは悪名高い「ブックマークの検索」を回避しますが、インデックスを厳密に必要以上に「広く」するという欠点がありました。
  • 実際、インデックス内の以前の列はunique rowをすでに識別していることが非常に多くあります。つまり、 "avoidingブックマーク検索」のメリット。
  • INCLUDE列は基本的に同じ利点をより効率的に可能にします。

[〜#〜] nb [〜#〜]指摘することが非常に重要なこと。通常、クエリを常にSELECT * ...として記述するという怠zyな習慣がある場合、インデックスのINCLUDE列のメリットはゼロになります。 all columnsを返すことで、基本的にブックマークのルックアップがどのような場合でも必要であることを確実にします。

17
Disillusioned

最初のインデックスで、Index pageのみPostalCodeがキー列であり、AddressLine1, AddressLine2, City, StateProvinceIDは、key/RID 調べる

テーブルが常にPostalCodeおよびこの列AddressLine1, AddressLine2, City, StateProvinceIDは、ろ過ではなくselectの一部になります

select AddressLine1, AddressLine2, City, StateProvinceID
from Person.Address 
Where PostalCode=  

2番目のインデックスのIndex page 5つのキー列がありますPostalCode, AddressLine1, AddressLine2, City, StateProvinceID

次のようなデータをフィルタリングする可能性がある場合、2番目のインデックスを優先します

Where PostalCode = And AddressLine1 = 

または

Where PostalCode = And AddressLine2 = 

または

Where PostalCode = And AddressLine1  = and AddressLine2 = 

等々..

いずれにせよ、インデックスの最初の列は、インデックスを利用するためのろ過の一部であるべきです

6

最初の例では、インデックス列:PostalCodeのみがインデックスツリーに格納され、他のすべての列はインデックスのリーフレベルに格納されます。これにより、インデックスのサイズが小さくなり、where、Join、group byを他の列に対してではなく、PostalCodeに対してのみ使用する場合に役立ちます。

2番目のインデックスでは、すべての列のすべてのデータがインデックスツリーに格納されます。これにより、インデックスが非常に大きくなりますが、WHERE/JOIN/GROUP BY/ORDER Byステートメントで列を使用する場合に役立ちます。

[列を含める]を選択すると、選択リストでデータが指定されたときに、データをより高速に取得できます。

たとえば、実行している場合:

SELECT PostalCode, AddressLine1, AddressLine2, City, StateProvinceID 
FROM Person.Address 
Where PostalCode= 'A1234'

これは、PostalCodeにインデックスを作成し、他のすべての列を含めることでメリットが得られます

一方、実行している場合:

SELECT PostalCode, AddressLine1, AddressLine2, City, StateProvinceID 
FROM Person.Address 
Where PostalCode= 'A1234' or City = 'London' or StateProvinceID = 1 or AddressLine1 = 'street A' or AddressLine2 = 'StreetB'

これは、インデックス内のすべての列を持つことにより多くの利益を得るでしょう

以下のリンクをご覧ください、これらはあなたのクエリに役立つかもしれません

含まれる列を持つインデックス: https://msdn.Microsoft.com/en-us/library/ms190806(v = sql.105).aspx

テーブルとインデックスの構成: https://msdn.Microsoft.com/en-us/library/ms189051(v = sql.105).aspx

2
user7415753