web-dev-qa-db-ja.com

すべての列を含む非クラスター化インデックスを持つ一時テーブル

背景:1日に1回、さまざまな集計値を計算するいくつかの一時テーブルが作成されます。それらはすべて同じ一意の識別子(私がPRIMARY KEYを作成するフィールド)を含んでいます。各テーブルには約2から8列の約100k行があります。その後、いくつかのJOINとUNION ALLが一時テーブルで実行されます。 Every一時テーブルのallのフィールドが使用されます。さらに、ほとんどの場合、すべての行も使用されます。最悪の場合、行の半分がどこかで使用され、残りの半分がどこかで使用されます。クエリが完了すると、結果がディスクに保存されるため、個人は残りの日のデータにアクセスできます。

質問:次のアプローチのどれがすべき最速である:

•一時テーブルにインデックスがない。

•すべての一時テーブルにクラスター化インデックスを作成します(一意の識別子のPRIMARY KEY宣言を使用)。

•すべての一時テーブルの残りの列を含めながら、一意の識別子に非クラスター化インデックスを作成します。

•最後の2つの箇条書きをまとめます。

Thoughts:4つのオプションすべてを同時に実行している間、各オプションのクエリコストは25%(バッチに対して)でした。ただし、最初の箇条書きが実行されると、(SELECTクエリの)実行プランに、各一時テーブルの残りの列を含めながら、一意の識別子に非クラスター化インデックスを作成する必要があると記載されています。

私はこれに少し困惑しています。すべての一時テーブルのすべてのフィールドと行を効果的に使用すると、なぜこれが推奨されるのですか?ヒープまたはクラスター化インデックスの方が優れていると思いませんか?

私にとって、ヒープを使用すると、インデックスの作成とデータの並べ替えのオーバーヘッドを最小限に抑えることができます。本質的にすべての行が必要なので、テーブルスキャンを実行しても害はありません。

一方、クラスター化インデックスは、他の2つの一時テーブルのJOINを介して作成される一時テーブルを改善し、JOINとUNION ALLに依存する最後のSELECTクエリを改善する必要があります。

関連メモ:400列と70M行の大きなテーブル-なぜばかげた数の列があるのか​​尋ねないでください-PRIMARY KEYのみを取得したクエリは、使用時に≈50倍高速でしたクラスタ化インデックスに関連しない非クラスタ化インデックス。

誰か洞察力があれば、感謝します。

6
basketballfan22

要約すると(コメントの一部の情報を含めるため)、1日1回、早朝に実行されるプロセスがあり、それぞれ2から8列の10万行の一時テーブルがいくつか作成されます。これは幅広い質問ですが、私の最初の反応は、すべてのテーブルに主キーを作成することです。性能が良ければ満足です。パフォーマンスが十分でない場合は、さらに調査してコードを改善する方法を見つけます。主キーを削除することは技術的にはオプションですが、一般的には一時テーブルにデータを入力するクエリを変更することでパフォーマンスの向上が見込めると思います。

ヒープは、クラスター化インデックスのないテーブルです。主キーは、クラスター化インデックスと同じ方法で定義する必要がないことに注意してください。実際、主キーでヒープを定義できます。私の知る限り、これはあまり一般的なことではありません。ワークロードにヒープを使用することには、いくつかの利点があります。

  1. データを挿入しても、並べ替えは行われません。クラスタ化インデックスのあるテーブルに10万行を挿入すると、テーブルにデータを設定するクエリによっては、データをソートする必要がある場合があります。すべての列またはクラスタリングキーのみをソートに含めることができます。
  2. SQL Server 2014以降、SELECT INTO構文を使用すると、挿入を並列で実行できます。クエリオプティマイザーは、データの推定サイズやMAXDOP設定などのさまざまな理由により、並列挿入を使用しないことを選択する場合があることに注意してください。

一般に、特にこのプロセスが何もない状態で早朝に実行される場合は、10万行の種類について心配する必要はありません。並列挿入は、このような少量のデータにとっても大きな助けにはならないでしょう。

このワークロードにヒープを使用することには、いくつかの欠点があります。

  1. データの整合性はありません。プロセスにバグがあるか、データが破損している可能性があります。これは、一時テーブルの主キーで以前に検出された可能性があります。
  2. データは並べ替えられないため、並べ替えられたデータを必要とするクエリプラン演算子(マージ結合演算子やクラスター化されたテーブルへの挿入など)では、明示的な並べ替えが必要になります。 3つのクエリで1つのテーブルを参照し、クエリオプティマイザが3回すべてデータをソートするとします。クエリプランでこれらの3つの並べ替えを回避するために、最初にディスク上のデータを並べ替えませんか?

私はあなたのプロセスについて何も知らないので、これらの点についてこれ以上言うのは難しいです。一時テーブルに対するクエリがMERGE JOINの恩恵を受ける可能性はありますが、ボリュームで大きな違いが出るとは思えません。

次に、クラスター化インデックスを持つテーブルについて説明します。前述のように、クラスター化インデックスは主キーと一致する必要はありませんが、両方が同じであるという最も一般的なデフォルトを想定します。 PRIMARY KEYをテーブル定義の一部としてインラインで定義すると、最終的にそれが終わります。

ワークロードのクラスター化インデックスを含むテーブルには、いくつかの利点があります。

  1. データの整合性!
  2. 並べ替えのメリットがあるクエリプランオペレーターは、データを既に正しい順序で並べ替えている可能性があります。たとえば、関連するテーブルからすべてのデータを取得している場合は特に、これによりマージ結合がより魅力的になります。
  3. クエリオプティマイザーは、特定の列が一意であることを知っている場合、より効率的なプランを選択できる場合があります。これの1つの例は、SQL Serverは、結合が多対多ではないことを知っている場合があり、これにより、より正確なカーディナリティの推定と結合演算子のコストが発生する可能性があります。

ワークロードのクラスター化インデックスを使用したテーブルには、いくつかの欠点があります。

  1. 一時テーブルへの並列挿入は、SQL Serverのどのバージョンでも使用できません。
  2. テーブルの生成には、明示的な並べ替えが必要になる場合があります。

長所と短所は、ほとんどがヒープテーブルの正反対ですが、驚くことではありません。

3番目と4つのオプションは、検討する価値がありません。すべての列を含むインデックスを作成できますが、データが複製されます。主キーを正しい方法で定義するだけで、すべての列を含む追加の非クラスター化インデックスを使用する必要がなくなります。 SQL Server Management Studioでは、テーブルにクラスター化インデックスを作成することはお勧めしません。

クラスター化インデックス/主キーと非クラスター化インデックスの1つの違いは、クラスター化インデックス/主キーではキー列にNULL値が許可されず、一意性制約が自動的に適用されることです。もちろん、同じ制限のある非クラスター化インデックスを作成することも可能です。

最終的に、実行できることは、さまざまなオプションを使用してワークロードをテストすることだけです。したがって、どのアプローチが最速になるかを明確に述べることはできません。 1セットのデータとクエリを使用すると、ヒープアプローチが最も高速になる場合があります。異なるデータとクエリのセットを使用すると、クラスター化テーブルのアプローチが最も高速になる場合があります。データ整合性の価値を軽視しないでください。ただし、データ整合性を適用する他の方法がある場合があります。

6
Joe Obbish