これに完全に対処するには、クエリのテーブル例に関する詳細情報が必要になりますが、次のとおりです。
- DateTime 列はそれ自体で高度に選択する必要があるため
TimeOperation
、最初の列としてのインデックスは、に対するクエリの大部分に対処する必要がありますTimeOperation
。
- すべての列をやみくもにインデックスに追加しないでください。また、含まれているインデックスにも追加しないでください。これにより、インデックス ページの密度が低下し、生産性が低下します (インデックスでテーブルを複製することになります)。
- データベース内のすべてのデータが を中心とし
TimeOperation
ている場合は、その周りにクラスター化インデックスを構築することを検討してください。
- クエリがある場合は、 (適切に選択的であると仮定して)
field1 = x
別のインデックスが必要です。つまり、クエリの WHERE 句にない場合はインデックスにありません。field1
TimeOperation
- はい、その通りです。SQL がインデックス内のレコードを検索するとき、残りの列を取得するために、キー (または RID)ルックアップをクラスターに戻す必要があります。非クラスター化インデックスに
select
ステートメント内の他の列が含まれている場合、ルックアップを回避できます。ただし、SELECT(*) を使用しているため、カバー インデックスが役立つ可能性は低いです。
編集
解説 - 選択性と密度についてはこちらで詳しく解説しています。たとえば、クエリTimeOperation
が少数の行しか返さない場合 (経験則は 5% 未満ですが、常にそうとは限りません)、インデックスは使用されますか。つまり、クエリは SQL がインデックスを選択するのに十分選択的TimeOperation
です。
基本的な出発点は次のとおりです。
CREATE TABLE [MyTable]
(
intID INT ID identity(1,1) NOT NULL,
field1 NVARCHAR(20),
-- .. More columns, which may be selected, but not filtered
TimeOperation DateTime,
CONSTRAINT PK_MyTable PRIMARY KEY (IntId)
);
そして、基本的なインデックスは
CREATE NONCLUSTERED INDEX IX_MyTable_1 ON [MyTable](TimeOperation);
CREATE NONCLUSTERED INDEX IX_MyTable_2 ON [MyTable](Field1);
クラスタリングの考慮事項/オプション
ほとんどのレコードが TimeOperation の昇順で「シリアル」に挿入されている場合、つまり intId と TimeOperation の両方が同時に増加する場合、クラスタリングを intID (デフォルト) のままにします (つまり、テーブル DDL はPRIMARY KEY CLUSTERED (IntId)
であり、とにかくデフォルトです)。
ただし、 と の間に相関関係がない場合、ほとんどのクエリがの形式である場合(および PK を に変更する) は、このクエリを改善する必要があります (理由: 連続した時間が一緒に保持されるため、読み取る必要のあるページが少なくなり、ブックマークの検索は回避されます)。さらに良いことに、 の値が一意であることが保証されている場合は、一意化子が回避されるため、密度が向上します。IntId
TimeOperation
SELECT * FROM [MyTable] WHERE TimeOperation between xx and yy
CREATE CLUSTERED INDEX CL_MyTable ON MyTable(TimeOperation)
PRIMARY KEY NONCLUSTERED (IntId)
TimeOperation
CREATE UNIQUE CLUSTERED INDEX CL_MyTable ON MyTable(TimeOperation)
注-この回答の残りの部分では、あなたIntId
とTimeOperations
が強く相関しているため、クラスタリングはIntId
.
カバリングインデックス
他の人が述べたように、あなたの使用SELECT (*)
は悪い習慣であり、とりわけ、カバーするインデックスが役に立たないことを意味します(例外はCOUNT(*)
)。クエリが SELECT(*) ではなく、たとえば
SELECT TimeOperation, field1
FROM
WHERE TimeOperation BETWEEN x and y -- and returns < 5% data.
次に、インデックスを変更しTimeOperation
て含めるfield1
CREATE NONCLUSTERED INDEX IX_MyTable ON [MyTable](TimeOperation) INCLUDE(Field1);
または両方をインデックスに追加する (最も一般的なフィルターを最初に追加するか、両方のフィルターが常に存在する場合は最も選択的なフィルターを最初に追加する)
CREATE NONCLUSTERED INDEX IX_MyTable ON [MyTable](TimeOperation, Field1);
どちらもrid / keyルックアップを回避します。2 番目の (,) オプションは、TimeOperation と Field1 の両方が WHERE または HAVING 句でフィルター処理されるクエリに対応します。
Re : (TimeOperation, Field1) のインデックスと個別のインデックスの違いは何ですか?
例えば
CREATE NONCLUSTERED INDEX IX_MyTable ON [MyTable](TimeOperation, Field1);
クエリには役に立たない
SELECT ... FROM MyTable WHERE Field1 = 'xyz';
インデックスは、TimeOperation を持つクエリにのみ役立ちます
SELECT ... FROM MyTable WHERE TimeOperation between x and y;
また
SELECT ... FROM MyTable WHERE TimeOperation between x and y AND Field1 = 'xyz';
お役に立てれば?