回答:
いくつかの理由を詳細に説明し、この機能の一般的な制限についても説明します。
まず、以下から:不足しているインデックス機能の制限:
- インデックスで使用される列の順序は指定しません。
このQ&Aに記載されているように、SQL Serverは、欠落したインデックスリクエストでキー列の順序をどのように決定しますか?、インデックス定義内の列の順序は、Equality vs Inequality述部によって決まり、次にテーブル内の列の順序位置によって決まります。
選択性には推測がなく、より良い順序が利用できる場合があります。それを把握するのはあなたの仕事です。
特別なインデックス
欠落しているインデックスリクエストは、次のような「特別な」インデックスもカバーしません。
欠落しているインデックスキー列は、次のような結果のフィルタリングに使用される列から生成されます。
欠落したインクルード列は、クエリに必要な列から生成されます:
非常に頻繁ですが、並べ替えやグループ化を行う列は、キー列として役立ちます。これは、制限の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できないものは次のとおりです。
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に頼らないでください。