既存のインデックスに新しいインデックスのすべての列が含まれているのに、なぜこの新しいインデックスを作成するとパフォーマンスが大幅に向上したのですか?


19

LogテーブルとLogItemテーブルがあります。私は両方からいくつかのデータを取得するクエリを書いています。数千がLogsあり、それぞれLogが最大125まで持つことができますLogItems

問題のクエリは複雑なのでスキップしています(誰かが重要だと思うなら、おそらく投稿できるでしょう)が、SSMS推定クエリプランを実行すると、新しい非クラスタ化インデックスによってパフォーマンスが最大100%向上することがわかりました。

Existing Index: Non-clustered
Key Colums (LogItem): ParentLogID, DateModified, Name, DatabaseModified

Query Plan Recommendation
CREATE NONCLUSTERED INDEX [LogReportIndex]
ON [dbo].[LogItem] ([ParentLogID],[DatabaseModified])

楽しみのために、この新しいインデックスを作成してクエリを実行しましたが、驚いたことに、クエリが実行されるまでに10秒以上かかるのに1秒かかりました。

既存のインデックスがこの新しいクエリをカバーすると想定したので、私のクエリは、新しいクエリで使用される列のみに新しいインデックスを作成するとパフォーマンスが向上するのはなぜですか?where句で使用される列の一意の組み合わせごとにインデックスを作成する必要がありますか?

注:これは、SQL Serverが結果をキャッシュしているためだとは思いません。インデックスを作成する前に約25〜30回クエリを実行しました。以下。


追加の非クラスター化インデックスを作成する前に、インデックスの使用に関して実際の実行計画は何を示しましたか?
トーマスストリンガー

100%向上したパフォーマンスとは何ですか?

@Shark良い質問です、わかりません。これが私の最初のパフォーマンスデバッグ状況です。私は今後もそれを確実につかむでしょう。それが言ったのは「Missing index」だけで、どのフィールドかを言った。

@JeffOこれは、SSMSが言ったことです。「クエリプロセッサは、次のインデックスを実装すると、クエリコストが100%改善されると推定しています。」

回答:


21

インデックス内の列の順序は重要です。フィルタリングにインデックスの列1と4が必要な場合、インデックスは役に立ちません。最初のN個の連続した列でフィルタリングする場合にのみ役立ちます。

これは、インデックスがツリーであるためです。ツリーのすべてのノードを効率的に選択することはできません。これらのノードは、およびのcolumn3 = something異なる値に属する他のすべての場所に散在しているためです。あなたが知っている場合でも、と同様、ツリー内の右の枝を配置すること非常に簡単ではありません。column1column2column1column2


(一般的に)そのテーブルにヒットする「where」句のセットごとに1つのインデックスが必要であると仮定しても安全でしょうか?

私はかつて、適切な順序でインデックスを使用することを確認するだけで、誰かのクエリの大幅な高速化を行いました。

1
@ネイト大まかに、はい。いくつかwhereは重複する可能性があるため、いくつかwhereのをうまくカバーするインデックスを作成できます。またはwhere、特定の列のインデックス付けはいずれにしても効果がないため(選択性が低い)、句の一部を無視できます。しかし、広くはい。

@Nate必要以上のインデックスは必要ありません。SQLが維持する必要のある各インデックスは、独自のオーバーヘッドを追加します。既存のインデックスの最初のN列と一致するようにWHERE句を並べ替えることができる場合、追加のインデックスを追加せずに非常に近くなります。
そのチャックガイ

1
@ChuckBlumreich where句内の列の順序は重要ではありません。サーバーは、既存のインデックスを最大限に活用するためにそれらを常に配置します。必要なすべてのwhere列を最初の列として含むインデックスを作成することだけが問題です。

12

リーディングエッジ指数のは重要なものです。

クエリがインデックスのリーディングエッジによって「カバー」されている限り、効率的です。通常、データベースインデックスはBツリーとして実装され、Bツリーの構造により、検索を特定の順序で実行する必要があるため、複合インデックスのフィールドの順序が重要になります。

「穴」がある場合、たとえばとで検索するがParentLogIDDatabaseModifiedインデックスのみがオンの{ParentLogID, DateModified, Name, DatabaseModified}場合{ParentLogID}、インデックスの一部のみを効率的に利用できます。

(注:一部の{DatabaseModified}DBMSは「スキップスキャン」でその部分を利用できますが、DBMSがそれを実行しても、通常のインデックスアクセスよりもはるかに効率が低下します)


したがって、私が持っColumns (a, b, c, d, e, f)ているほとんどのクエリが良い... WHERE A IN(...) AND B = 3インデックスIndex(a,b,c,d)である場合... WHERE A IN (...) AND D = 5、新しいインデックスを作成したIndex(a,d)ので、パフォーマンスが大幅に向上したのはなぜですか?

8
@ネイト-正しい。電話帳のように考えてください。誰かの名前だけを知っている場合、姓、名
JNK
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.