クエリがかなり遅いSQL Serverデータベースがあり、ロックとブロックがたくさんあります。
不足しているインデックスDMVとクエリプランを見ると、何の提案もありません。
何故ですか?
その理由のいくつかをより詳細に検討し、機能の一般的な制限のいくつかについても話します。
まず、以下から: 不足しているインデックス機能の制限 :
- インデックスで使用される列の順序は指定しません。
このQ&Aに記載されているように、- SQL Serverは欠落しているインデックスリクエストのキー列の順序をどのように決定するのですか? 、インデックス定義の列の順序は、Equal対Inequality述語によって決まり、次に列の序数がテーブル。
選択性に関する推測はなく、より良い順序が利用できる可能性があります。それを理解するのはあなたの仕事です。
特別なインデックス
欠落しているインデックス要求も、次のような「特別な」インデックスをカバーしません。
欠落したインデックスキー列は、次のような結果のフィルターに使用される列から生成されます。
Missing Index Included列は、次のようなクエリで必要な列から生成されます。
かなり頻繁にではありますが、並べ替えやグループ化に使用する列は、キー列として役立ちます。これは、制限の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 23 を有効にすると、欠落しているインデックス要求はログに記録されません。これが有効になっているかどうかを確認するには、次のコマンドを実行します。
_DBCC TRACESTATUS;
_
インデックスの再構築 は、欠落しているインデックス要求をクリアします。そのため、Hi-Ho-Silver-Awayに進む前に、2番目にすべてのインデックスを再構築し、断片化のイオタがこっそり侵入します。それを行うたびに、クリアしている情報について考えてください。
とにかく、 インデックスの最適化が役に立たない理由 について考えてみることもできます。 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がそれを理解するのを助けることを期待しないでください。