web-dev-qa-db-ja.com

実行プランインデックスの提案-類似クエリの違い

私はこのテーブルのクエリを分析しようとしています:

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を超える行があります。

2
Ofiris

一部のコンテキスト

最初に観察することは、tidがインデックスの先頭の列であるため、クラスター化インデックスはt列のルックアップを支援しないことです。

キーのttidの順序を逆にした場合、インデックスのヒントがなくなり、新しいインデックスを追加しなくてもクエリがより高速に実行されると思います。

特定の回答

2番目のクエリプランがインデックスを提案しない最も可能性の高い理由は、tidの新しいフィルターがテーブル内のすべての値の約30%以上を選択することです。その場合、SQL Serverは通常、インデックスを探すよりもテーブルスキャンを優先します(これがより優れた戦略であるため)。したがって、インデックスを提案することはもはや適切なことではありません。 1つではなく2つの値を選択すると、オプティマイザでこの30%定数の転換点になる可能性があります

この効果を調べるには、次のようにしてインデックスヒントを強制的に返すことができます。

SELECT *
FROM [dbo].[Values] WITH (FORCESEEK)
WHERE  [tid] = 1 or [tid] = 2

..しかし、効果を調査するためだけに、本番環境ではこれを行わないでください。

インクルードする理由

インクルードがあるのは、実行されなかった場合に実行されるためです。

  1. tidの新しく作成されたインデックスで探している値を見つけます
  2. メインインデックス(主キー)に移動して、列vおよびtの値を取得します。

INCLUDEは、すべての列がインデックスに含まれていることを確認するため、2番目の手順は必要ありません。ちなみに、これはSELECT *を避けるべき理由の1つです。

4
Thomas Kejser