SQL ServerのDMVまたはクエリプランに欠落しているインデックスリクエストがないのはなぜですか?


14

クエリがかなり遅いSQL Serverデータベースがあり、ロックとブロックがたくさんあります。

欠落しているインデックスDMVとクエリプランを見ると、提案はありません。

何故ですか?

回答:


17

インデックス要求が欠落していない理由はたくさんあります!

いくつかの理由を詳細に説明し、この機能の一般的な制限についても説明します。

一般的な制限

まず、以下から:不足しているインデックス機能の制限

  • インデックスで使用される列の順序は指定しません。

このQ&Aに記載されているように、SQL Serverは、欠落したインデックスリクエストでキー列の順序をどのように決定しますか?、インデックス定義内の列の順序は、Equality vs Inequality述部によって決まり、次にテーブル内の列の順序位置によって決まります。

選択性には推測がなく、より良い順序が利用できる場合があります。それを把握するのはあなたの仕事です。

特別なインデックス

欠落しているインデックスリクエストは、次のような「特別な」インデックスもカバーしません。

  • クラスター化
  • フィルター済み
  • 仕切り
  • 圧縮された
  • XML編
  • 空間編集
  • Columnstore-d
  • インデックス付きビュー

どの列が考慮されますか?

欠落しているインデックスキー列は、次のような結果のフィルタリングに使用される列から生成されます。

  • 参加する
  • WHERE句

欠落したインクルード列は、クエリに必要な列から生成されます:

  • 選択する
  • GROUP BY
  • ORDER BY

非常に頻繁ですが、並べ替えやグループ化を行う列は、キー列として役立ちます。これは、制限の1つに戻ります。

  • インデックス設定を微調整することは意図されていません。

たとえば、LastAccessDateにインデックスを追加するとソート(およびディスクへのスピル)が不要になりますが、このクエリは欠落したインデックスリクエストを登録しません。

SELECT TOP (1000) u.DisplayName
FROM dbo.Users AS u
ORDER BY u.LastAccessDate DESC;

ナッツ

ロケーションに関するこのグループ化クエリも同様です。

SELECT TOP (20000) u.Location
FROM dbo.Users AS u
GROUP BY u.Location

ナッツ

それはあまり役に立たないようです!

ええ、しかし、それは何もないよりはましです。泣いている赤ちゃんのような行方不明のインデックスリクエストを考えてください。あなたは問題があることを知っていますが、その問題が何であるかを理解するのは大人としてあなた次第です。

あなたはまだ私がそれらを持っていない理由をまだ教えていません...

リラックス、バッコ。私たちはそこに着いています。

トレースフラグ

TF 2330を有効にすると、欠落しているインデックスリクエストはログに記録されません。これが有効になっているかどうかを確認するには、次を実行します。

DBCC TRACESTATUS;

インデックスの再構築

インデックス再構築すると、欠落しているインデックスリクエストがクリアされます。そのため、Hi-Ho-Silver-Awayを実行する前に、断片化のイオタが潜入するすべてのインデックスを再構築する前に、それを行うたびに消去する情報について考えてください。

とにかく、インデックスの最適化が役に立たない理由について考えることもできます。Columnstoreを使用している場合を除きます。

インデックスの追加、削除、または無効化

インデックスを追加、削除、または無効にすると、そのテーブルの欠落しているインデックスリクエストがすべてクリアされます。同じテーブルで複数のインデックスの変更を行っている場合は、変更を行う前にそれらをすべてスクリプト化してください。

些細な計画

計画が十分に単純で、インデックスアクセスの選択が十分に明白であり、コストが十分に低い場合、簡単な計画が得られます。

これは事実上、オプティマイザーが行うコストベースの決定がなかったことを意味します。

ポール・ホワイト経由:

トリビアルプランのメリットを享受できるクエリの種類の詳細は頻繁に変更されますが、結合、サブクエリ、不等式述語などによって、一般的にこの最適化が妨げられます。

計画が簡単な場合、追加の最適化フェーズは検討されず、欠落しているインデックスは要求されません

これらのクエリとその計画の違いをご覧ください。

SELECT *
FROM dbo.Users AS u
WHERE u.Reputation = 2;

SELECT *
FROM dbo.Users AS u
WHERE u.Reputation = 2
AND 1 = (SELECT 1);

ナッツ

最初の計画は簡単で、リクエストは表示されません。バグにより、欠落したインデックスがクエリプランに表示されない場合があります。ただし、通常は欠落しているインデックスDMVでより確実にログに記録されます。

可搬性

インデックスがあってもオプティマイザーがインデックスを効率的に使用できない述語は、ログに記録されない場合があります。

一般にSARGできないものは次のとおりです。

  • 関数でラップされた列
  • 列+ SomeValue = SomePredicate
  • 列+ AnotherColumn = SomePredicate
  • 列= @Variable OR @Variable IS NULL

例:

SELECT *
FROM dbo.Users AS u
WHERE ISNULL(u.Age, 1000) > 1000;


SELECT *
FROM dbo.Users AS u
WHERE DATEDIFF(DAY, u.CreationDate, u.LastAccessDate) > 5000


SELECT *
FROM dbo.Users AS u
WHERE u.UpVotes + u.DownVotes > 10000000


DECLARE @ThisWillHappenWithStoredProcedureParametersToo NVARCHAR(40) = N'Eggs McLaren'
SELECT *
FROM dbo.Users AS u
WHERE u.DisplayName LIKE @ThisWillHappenWithStoredProcedureParametersToo 
      OR @ThisWillHappenWithStoredProcedureParametersToo IS NULL;

これらのクエリはいずれも、欠落しているインデックスリクエストを登録しません。これらの詳細については、次のリンクをご覧ください。

すでに大丈夫なインデックスがあります

このインデックスをご覧ください:

CREATE INDEX ix_whatever ON dbo.Posts(CreationDate, Score) INCLUDE(OwnerUserId);

このクエリでは問題ありません:

SELECT p.OwnerUserId, p.Score
FROM dbo.Posts AS p
WHERE p.CreationDate >= '20070101'
AND   p.CreationDate < '20181231'
AND   p.Score >= 25000
AND 1 = (SELECT 1)
ORDER BY p.Score DESC;

計画はシンプルなシークです...

ナッツ

しかし、主要なキー列は選択性の低い述語のためのものであるため、必要以上の作業を行うことになります。

テーブル「投稿」。スキャン数13、論理読み取り136890

インデックスキー列の順序を変更すると、作業が大幅に少なくなります。

CREATE INDEX ix_whatever ON dbo.Posts(Score, CreationDate) INCLUDE(OwnerUserId);

ナッツ

そして、大幅に少ない読み取り:

テーブル「投稿」。スキャンカウント1、論理読み取り5

SQL Serverがインデックスを作成しています

特定のケースでは、SQL Serverはインデックススプールを介してその場でインデックスを作成することを選択します。索引スプールが存在する場合、欠落した索引要求は存在しません。インデックスを自分で追加するのは良い考えかもしれませんが、それを理解するのに役立つSQL Serverに頼らないでください。

ナッツ

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.