0

私は通常のsqlserverテーブルを持っています

intID(primary key),field1,field2,manyotherfields..., datetime TimeOperation

私のさまざまな種類のクエリの 99% は で始まりTimeOperation BETWEEN startTime AND endTime、次にselect * (or count(*)) where fieldA=xxxで始まり、他の小さなテーブルと結合します。 select *多かれ少なかれ、すべてのフィールドが必要だからです。

...にインデックスを作成したのは明らかTimeOperationですが、パフォーマンスが十分ではないため、インデックスキー列またはインデックスに含まれる列をいくつか追加したいのですが、少し混乱しています。

2つの違いはわかりますが、それぞれの場合に列を追加することが速度とサイズにどの程度影響するかはわかりません。

最大の改善点は、すべての列を含むインデックスを作成することだと思いますが、そうですか? (でもスペース的に余裕がない)

field1=xxxたとえば、よく使用する場合はfield1、インデックス キー列 ( の後TimeOperation) に追加すると、パフォーマンスが向上しますよね?

また...列が含まれているインデックスがどのように機能するかを確認するために:TimeOperation特定の範囲の行を選択すると、SQL は関心のある行の TimeOperation インデックスを探します。すべてのテーブルをスキャンするよりも高速です。インデックスでは、TimeOperation の値が昇順になっていますが、正しいですか? しかし、その後、すべてのデータが必要になり、それらの行の残りのデータ フィールドがすべて必要になります...データを取得するために SQL はどのように動作しますか? インデックス内のそれらの行への一種のブックマークがあると思いますよね? しかし、テーブルを複数回ヒットする必要があります...したがって、インデックスにすべての列を含めると、テーブルをヒットする時間が節約されます。正しいですか?

ありがとう!マティア

4

2 に答える 2

1

これに完全に対処するには、クエリのテーブル例に関する詳細情報が必要になりますが、次のとおりです。

  • DateTime 列はそれ自体で高度に選択する必要があるためTimeOperation、最初の列としてのインデックスは、に対するクエリの大部分に対処する必要がありますTimeOperation
  • すべての列をやみくもにインデックスに追加しないでください。また、含まれているインデックスにも追加しないでください。これにより、インデックス ページの密度が低下し、生産性が低下します (インデックスでテーブルを複製することになります)。
  • データベース内のすべてのデータが を中心としTimeOperationている場合は、その周りにクラスター化インデックスを構築することを検討してください。
  • クエリがある場合は、 (適切に選択的であると仮定して)field1 = x別のインデックスが必要です。つまり、クエリの WHERE 句にない場合はインデックスにありません。field1TimeOperation
  • はい、その通りです。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 を に変更する) は、このクエリを改善する必要があります (理由: 連続した時間が一緒に保持されるため、読み取る必要のあるページが少なくなり、ブックマークの検索は回避されます)。さらに良いことに、 の値が一意であることが保証されている場合は、一意化子が回避されるため、密度が向上します。IntIdTimeOperationSELECT * FROM [MyTable] WHERE TimeOperation between xx and yyCREATE CLUSTERED INDEX CL_MyTable ON MyTable(TimeOperation)PRIMARY KEY NONCLUSTERED (IntId)TimeOperationCREATE UNIQUE CLUSTERED INDEX CL_MyTable ON MyTable(TimeOperation)

-この回答の残りの部分では、あなたIntIdTimeOperationsが強く相関しているため、クラスタリングは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';

お役に立てれば?

于 2012-09-14T14:40:59.447 に答える
0

最も基本的なインデックスは、バックグラウンドで「ハイパーツリー」構造のレイヤーを作成します。これにより、SQL エンジンは、インデックス付きの列の特定の値を持つ行をより簡単に見つけることができます。各インデックスは、バイナリ検索 (logN パフォーマンス) を使用してテーブルのデータに「ドリルダウン」するさまざまな方法を作成します。追加するインデックスごとに、そのインデックスによる選択が高速になりますが、挿入/更新が遅くなります (データを入力してからインデックスを作成する必要があります)。

したがって、通常は、レコードのフィルタリングによく使用される列の組み合わせに対してインデックスを作成する必要があります。実際、TimeOperation にインデックスを作成し、TimeOperation だけを作成します。

テーブルのすべての列、特にこのような幅の広い列を含むインデックスを単純に作成しないでください。

于 2012-09-14T14:42:38.497 に答える