web-dev-qa-db-ja.com

クラスター化インデックスシークのパフォーマンスを向上させる方法

実行が非常に遅いクエリのパフォーマンスを改善しようとしています。 実際の実行計画; Clustered Index Seekが82%を占めていることがわかりました。 Index Seekのパフォーマンスを改善する方法はありますか?以下は、実行計画からの問題Index Seekと、使用しているインデックスおよびテーブルのイメージです。

alt text http://img340.imageshack.us/img340/1346/seek.png

インデックス:

/****** Object:  Index [IX_Stu]    Script Date: 12/28/2009 11:11:43 ******/
CREATE CLUSTERED INDEX [IX_Stu] ON [dbo].[stu] 
(
 [StuKey] ASC
)WITH (PAD_INDEX  = OFF, SORT_IN_TEMPDB = OFF, DROP_EXISTING = OFF, IGNORE_DUP_KEY = OFF, ONLINE = OFF) ON [PRIMARY]

表(簡潔にするために一部の列を省略):

CREATE TABLE [dbo].[stu](
 [StuCertKey] [int] IDENTITY(1,1) NOT NULL,
 [StuKey] [int] NULL
 CONSTRAINT [PK_Stu] PRIMARY KEY NONCLUSTERED 
(
 [StuCertKey] ASC
)WITH (PAD_INDEX  = OFF, IGNORE_DUP_KEY = OFF, FILLFACTOR = 80) ON [PRIMARY]
) ON [PRIMARY]
30
Abe Miessler

ここで一般化していますが...

クラスタ化インデックスシークは、ほとんどの場合、最良のシナリオです。パフォーマンスを改善するために考えられる唯一の方法は次のとおりです。

  • 可能であれば、クエリを更新して、返される行/列を減らします。
  • インデックスを最適化または再構築します。
  • インデックスを複数のディスク/サーバーに分割します。

138行しか返されず、それが遅い場合...他のプロセスによってブロックされている可能性がありますか?これを単独でテストしていますか、それとも他のユーザー/プロセスが同時にオンラインですか?または、ディスク障害などのハードウェアの問題である可能性もあります。

21
Aaronaught

クラスター化インデックスのシークは、非クラスター化インデックスが使用されている場合に発生し、必ずしも不良ではありません。

次のクエリを検討してください。

SELECT s.StuKey, s.Name, s.Address, s.City, s.State FROM stu s WHERE State='TX'

StuKeyにクラスター化インデックスしかない場合、SQL Serverには1つのオプションしかありません。State= "TX 'の行を探してテーブル全体をスキャンし、それらの行を返す必要があります。

状態に非クラスター化インデックスを追加する場合

CREATE INDEX IX_Stu_State on Stu (State)

現在、SQLサーバーには新しいオプションがあります。非クラスター化インデックスを使用してシークすることを選択できます。これにより、State = 'TX'の行が生成されます。ただし、残りの列をSELECTで返すには、各行に対してクラスター化インデックスシークを実行してそれらの列を検索する必要があります。

クラスタ化インデックスのシークを減らしたい場合は、追加の列を含めることでインデックスを「カバー」することができます。

 CREATE INDEX IX_Stu_State2 on Stu (State) INCLUDE (name, address, city )

このインデックスには、上記のクエリに回答するために必要なすべての列が含まれています。クエリは、State = 'TX'の行のみを返すインデックスシークを実行し、追加の列を非クラスター化インデックスから引き出すことができるため、クラスター化インデックスシークはなくなります。

13
StrayCatDBA

138行を返すクラスター化インデックス範囲のシークは問題ではありません。

技術的には、クラスター化インデックスを狭くすることにより、シークパフォーマンスを向上させることができます。

  • 'out of out from row 'を1に設定し、テーブルを最初から再作成して、すべての変数を別の割り当てユニットに追い出します。
  • enable ページ圧縮 (SQL 2008 EEのみ)。

両方がIOと物理読み取りをヒットする必要性を減らすため、範囲シーク時間に非常に劇的な影響を与える可能性があります。もちろん、通常、結果は他の多くのどの列を投影するかなどの要素(投影列をBLOB割り当て単位に排除すると、特定のクエリに実際に悪影響が生じる可能性があります)。依存します。

しかし、私が言うように、これがあなたの本当の問題だとは非常に疑っています。計画の選択部分と独自の分析結果のみを投稿しました。真の根本原因は完全に別の場所にある可能性があります。

8
Remus Rusanu

考え...

  • IX_Stuがクラスター化されるのはなぜですか?内部的に、SQL Serverは、4バイトの「一意名」を一意でないクラスター化インデックスに追加します。正当化とは何ですか?これもあなたのPKを膨らませます

  • 実行している実際のクエリは何ですか?

  • 最後に、なぜFILLFACTOR 80%ですか?

編集:

  • 「通常の」FILLFACTORは90%ですが、これは経験則です

  • 11の結合クエリ?それはおそらくあなたの問題です。 JOIN、WHERE句などは何ですか?全文プランとは何ですか?

3
gbn

いくつかの一般的なアドバイス:クエリの最適化を行う必要がある場合、実行計画がどうあるべきかを書き出すことから始めます。

実行計画がどうあるべきかを決定したら、実際のクエリがこの計画に適合するようにします。これを行うための手法はDBMSごとに異なり、DBMSの異なるバージョン間で転送する必要はありません。

留意すべきことは、DBMSは一度に1つの結合しか実行できないことです。2つの初期テーブルから開始し、それらを結合してから、その操作の結果を取得して次のテーブルに結合します。各ステップの目標は、中間結果セットの行数を最小化することです(より正確には、中間結果を生成するために読み取る必要があるブロック数を最小化することですが、これは一般に最少行を意味します)。

2
kdgregory

[〜#〜] where [〜#〜]条件を次のようにハードコーディングするとどうなりますか。

SELECT StuCertKey, StuKey FROM stu 
WHERE stuKey in (/* list 50 values of StuKey here */)

それでも非常に遅い場合は、何らかの内部問題が発生しています。より高速な場合、インデックスはボトルネックではありません。JOINsを作成するためにやっているのは[〜#〜] where [〜#〜]フィルターです。

ご了承ください SELECT *は、大きな列が多数ある場合、特にBLOBがある場合は非常に遅くなる可能性があります。

1
egrunin

インデックスの統計を確認してください。

クラスタ化インデックス統計を再計算すると、問題が解決します。

私の場合、40Mのレコードを30個探していました。実行計画では、クラスタ化インデックスを通過すると言われていますが、約200ミリ秒かかりました。インデックスは最適化されていません。統計を再計算した後、10ms以内に完了しました!

1
coolboy88

このインデックスをメンテナンスしましたか?デフラグが好きですか?かなりの費用がかかる(120.381)ことは本当に奇妙に思えます。インデックスシークは最速のインデックス操作であり、それほど長くはかかりません。クエリを投稿できますか?

1
Pedro

インデックスを再構築し、統計を計算しますか?

私がそれをスピードアップすると考えることができる他の唯一の方法は、テーブルを分割することです。これは可能かもしれないし不可能かもしれません。

0
Paul Creasey