web-dev-qa-db-ja.com

SQL Serverでの非クラスター化インデックスの使用

私は2つのインデックスを持っています:

CREATE NONCLUSTERED INDEX [IX_1] ON [dbo].[TableA]
(
    [Column1] ASC,
    [Column2] ASC
)

CREATE NONCLUSTERED INDEX [IX_2] ON [dbo].[TableA]
(
    [Column3] asc
)

今私は2つのアップデートがあります:

Update TableA SET Column3='' where Column1=''

上記の更新では、インデックス1を使用してから、クラスター化インデックスへのキールックアップを使用していました。

Update TableA SET Column3='' where Column3=''

この更新は2番目のインデックスを使用していました

更新に基づいて、2番目のインデックスを削除して最初のインデックスを更新できると思いました

CREATE NONCLUSTERED INDEX [IX_1] ON [dbo].[TableA]
(
  [Column1] ASC,
  [Column2] ASC
)
INCLUDE(Column3 asc)

したがって、更新されたインデックスでは、最初の更新が正常に機能し、更新された非クラスター化インデックスが使用されますが、2番目の更新では、column3に非クラスター化インデックスを作成するように求められます。

それから私は試しました

CREATE NONCLUSTERED INDEX [IX_1] ON [dbo].[TableA]
(
  [Column1] ASC,
  [Column2] ASC,
  [Column3] asc
)

しかし、2回目の更新では、新しい非クラスター化インデックスを作成するように求められます。

しかし、私が理解しているのはColumn1Column2Column3は非クラスター化インデックスのルートレベルに存在します

2
user185981

したがって、更新されたインデックスでは、最初の更新が正常に機能し、更新された非クラスター化インデックスが使用されますが、2番目の更新では、column3に非クラスター化インデックスを作成するように求められます。

アップデートは常に正常に動作します。これは頻繁に実行する更新クエリですか?
一般に(追加の)非クラスター化インデックスは挿入を遅くするためです。

すべてのデータはクラスター化インデックス(CIX)にあります。非クラスター化インデックス(NCIX)はクラスター化インデックスのコピーですが、通常はクラスター化インデックスとは異なる方法で指定する順序で指定します。

TableA SET Column3 = ''を更新します。ここで、Column1 = ''です。

上記の更新では、最初にインデックスを使用し、次にクラスター化インデックスへのキー検索を使用していました。

TableA SET Column3 = ''を更新します(Column3 = ''の場合)

この更新は2番目のインデックスを使用していました

最初のクエリでは、サーバーは「Column1 =」の場所を調べる必要があります。これを行う最も速い方法は、Column1でsortedであるNCIXを使用し、CIXでレコードを検索することです(おそらくそうではありません)。

2番目のクエリでは、Column3でsortedであるため、他のインデックスを使用します

更新に基づいて、2番目のインデックスを削除して最初のインデックスを更新できると思いました

残念ながら、列を含めると、並べ替えには使用されません。

[dbo]。[TableA]に非クラスター化インデックス[IX_1]を作成します

[列1] ASC、
[列2] ASC、
[列3] asc

このNCIXでは最後にソートされるため、サーバーがレコードをすばやく見つけるのに十分な順序でソートされていない可能性があります。

Column1、Column2、Column3でソートするこの例を見てください。

Product      | Category   | Price 
----------------------------------- 
Apple        | Fruit      | 1.10  
Apple pie    | Pastry     | 5.00  
Apple Iphone | Electronic | 899.00  
Apple Watch  | Electronic | 459.00  
Bananas      | Fruit      | 1.50
Pear         | Fruit      | 1.25  
Pineapple    | Fruit      | 2.00  

価格がいたるところに表示されていますか? 「インデックス」の2列目も「ソート」されていませんか?
サーバーは適切な価格を見つけるためにインデックス/テーブル全体をスキャンする必要があります。

これが、Column3のみに新しいインデックスを推奨する理由です。しかし、正直なところ、このクエリを頻繁に実行しないと、このためのインデックスが作成されない限り、インデックスが増えると挿入と更新に時間がかかります(すべてに最新の値が必要なため)。

2
DrTrunks Bell

クラスタ化インデックス:キー列に従ってソートされた順序でページのテーブルデータを格納するのに役立ちます。つまり、ソートされたテーブル(クラスター化テーブル)と言えます。

非クラスター化インデックス:IAM(インデックス割り当てマップ)ページにキー値を保存します。ページIDや行オフセットなどの行アドレスとともに、データページで行を見つけるためのクエリに役立ちます。

つまり、HEAPまたはクラスター化テーブルにクラスター化インデックスを作成した後、キー列の値を2回保存することになります。 1つはデータページにあり、もう1つはインデックスページにあります。

例.

あなたはテーブルを持っています

CREATE TABLE tbe_TableName
(
Column_1 [datatype],
Column_2 [datatype],
Column_3 [datatype],
Column_4 [datatype],
Column_5 [datatype]
Index IDX_Clus CLUSTERED (Column_1)
)

Column_1には、クラスター化インデックスIDX_Clusと非クラスター化インデックスがあります。したがって、SQL ServerはColumn_1の値をデータページとインデックスページに2回書き込みます。

今あなたの質問に来ます。

first update statementを実行すると、データベースに値が2回書き込まれます。

  1. IX_2の索引ページ
  2. クラスタ化テーブルのデータベースページ

したがって、オプティマイザは、IDX_1からのデータアドレスでキー値を検索し、キールックアップを使用して、クラスタ化されたテーブルのデータページを検索し、指定された値をそこに書き込みます。

2番目の更新ステートメント

最初のステートメントとほとんど同じですが、インデックスページとデータページにも2回値を書き込みます。

INCLUDE Column_3をインデックスに追加しても、同じプロセスが実行されます。

注:テーブルに非クラスター化インデックスを作成すると、ディスク上の領域が多くなり、書き込みパフォーマンスが低下します。

インデックスにすべての列を含めること、またはテーブルのすべての列にインデックスを作成することは、データ複製のようなものです。

だから、私はあなたがブレントによって 高価なキー検索 を通過して決定することをお勧めします。

ありがとう!

2
Rajesh Ranjan