私はこのテーブルのクエリを分析しようとしています:
CREATE TABLE [dbo].[Values](
[tid] [smallint] NOT NULL,
[t] [datetime2](3) NOT NULL,
[v] [real] NOT NULL,
CONSTRAINT [PK_Values_Unique] PRIMARY KEY CLUSTERED
(
[t] ASC,
[tid] ASC
)WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON) ON [PRIMARY]
) ON [PRIMARY]
SQL Server Management Studioを使用して、いくつかの推定実行プランを確認しています- 最初のクエリ。
SELECT *
FROM [dbo].[Values]
WHERE [tid] = 1
このクエリのEstimated Execution Planを表示すると、次の結果が得られます。
CREATE NONCLUSTERED INDEX [<Name of Missing Index, sysname,>]
ON [dbo].[Values] ([tid])
INCLUDE ([timestamp],[v])
私は理解できますが、tid
が提案されている理由は完全にはわかりませんが、INCLUDE
ですばやく調べたいと思います。
次に、別のtid
と同じである2番目のクエリ(別のtid)を試しました。
SELECT *
FROM [dbo].[Values]
WHERE [tid] = 1 or [tid] = 2
しかし、現在[〜#〜] ssms [〜#〜]は、以前のインデックスを示唆していません。
なぜ[〜#〜] ssms [〜#〜]は最初のクエリにINDEXを提案しますが、2番目のクエリには提案しませんが、かなり同じです。 ?
この提案されたINDEXを追加することは、両方のタイプのクエリに役立ちますか?
編集:このテーブルには2 * 10 ^ 9を超える行があります。
一部のコンテキスト
最初に観察することは、tid
がインデックスの先頭の列であるため、クラスター化インデックスはt
列のルックアップを支援しないことです。
キーのt
とtid
の順序を逆にした場合、インデックスのヒントがなくなり、新しいインデックスを追加しなくてもクエリがより高速に実行されると思います。
特定の回答
2番目のクエリプランがインデックスを提案しない最も可能性の高い理由は、tid
の新しいフィルターがテーブル内のすべての値の約30%以上を選択することです。その場合、SQL Serverは通常、インデックスを探すよりもテーブルスキャンを優先します(これがより優れた戦略であるため)。したがって、インデックスを提案することはもはや適切なことではありません。 1つではなく2つの値を選択すると、オプティマイザでこの30%定数の転換点になる可能性があります
この効果を調べるには、次のようにしてインデックスヒントを強制的に返すことができます。
SELECT *
FROM [dbo].[Values] WITH (FORCESEEK)
WHERE [tid] = 1 or [tid] = 2
..しかし、効果を調査するためだけに、本番環境ではこれを行わないでください。
インクルードする理由
インクルードがあるのは、実行されなかった場合に実行されるためです。
tid
の新しく作成されたインデックスで探している値を見つけますv
およびt
の値を取得します。INCLUDEは、すべての列がインデックスに含まれていることを確認するため、2番目の手順は必要ありません。ちなみに、これはSELECT *を避けるべき理由の1つです。