主な考慮事項
ヒープとクラスタ化されたテーブルの1つの重要な利点に加えて、どちらの方法にも当てはまる3番目の考慮事項があります。
ヒープは間接的な層を節約します。インデックスには行IDが含まれており、ディスクの場所を直接(実際にはそうではありませんが、できる限り直接)指し示しています。したがって、ヒープに対するインデックスシークのコストは、クラスター化されたテーブルに対する非クラスター化インデックスシークの約半分になります。
クラスター化インデックスは、(ほぼ)無料のインデックスのおかげで、本質的にソートされます。クラスタリングインデックスはデータの物理的な順序に反映されるため、実際のデータ自体の上部に占めるスペースは比較的小さく、もちろん保存する必要があります。物理的に順序付けられているため、このインデックスに対する範囲スキャンは開始点をシークし、非常に効率的に終了点に沿って圧縮できます。
ヒープ上のインデックスは、64ビットのRIDを参照します。前述のように、クラスタ化されたテーブルの非クラスタ化インデックスは、クラスタリングキーを参照します。これは、より小さく(32ビットINT
)、同じ(64ビットBIGINT
)、またはより大きく(48ビットDATETIME2()
と32ビットINT
、または128ビットGUID)。明らかに、より広い参照は、より大きくより高価なインデックスになります。
スペース所要量
これらの2つのテーブルでは:
CREATE TABLE TmpClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpClustered ADD CONSTRAINT PK_Tmp1 PRIMARY KEY CLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp1 ON TmpClustered (ID2)
CREATE TABLE TmpNonClustered
(
ID1 INT NOT NULL,
ID2 INT NOT NULL
)
ALTER TABLE TmpNonClustered ADD CONSTRAINT PK_Tmp2 PRIMARY KEY NONCLUSTERED (ID1)
CREATE UNIQUE INDEX UQ_Tmp2 ON TmpNonClustered (ID2)
...それぞれ8.7 Mレコードが読み込まれ、両方のデータに必要なスペースは150 MBでした。クラスタ化テーブルのインデックス用に120 MB、非クラスタ化テーブルのインデックス用に310 MB。これは、クラスター化インデックスがRIDよりも狭く、クラスター化インデックスの大部分が「無料」であることを反映しています。上の一意のインデックスがない場合、ID2
必要なインデックススペースは、非クラスタ化テーブルでは155 MB(予想どおり半分)に低下しますが、クラスタ化PK ではわずか150 KBになり、ほとんどゼロになります。
したがって、32ビットインデックス(合計で64ビット、名目上)のクラスター化テーブル内の32ビットフィールドの非クラスター化インデックスは120 MBを必要とし、64ビットのヒープ内の32ビットフィールドのインデックスはRID(合計96ビット、名目上)は155 MBで、64ビットキーから96ビットキーへの移行が単純に予想される50%の増加より少し少ないですが、もちろん、オーバーヘッドがあり、サイズの効果的な差が小さくなります。
2つのテーブルにデータを取り込み、インデックスを作成するには、各テーブルで同じ時間がかかりました。スキャンまたはシークを含む簡単なテストを実行したところ、テーブル間に重要なパフォーマンスの違いは見られませんでした。この論文は、高度な同時アクセスの場合に大きな違いを示しています。なぜそれが起こるのかはわかりませんが、できれば、大量のOLTPシステムを使用している私よりも経験のある人が教えてくれることを願っています。
ランダム可変長データを40バイトまで追加しても、この等価性はそれほど変わりませんでした。INT
sをワイドUUIDに置き換えることもしませんでした(各テーブルはほぼ同じ程度に遅くなりました)。走行距離は異なる場合がありますが、ほとんどの場合、どの種類よりもインデックスが利用可能かどうかが重要です。
小片
テーブルがヒープであるか、インデックスがクラスター化インデックスではないため、非クラスター化インデックスに対して範囲スキャンを実行するには、インデックスをスキャンしてから、ヒットごとにテーブルを検索します。これは非常に高価になる可能性があるため、テーブルをスキャンする方が安価な場合があります。ただし、カバリングインデックスを使用してこの問題を回避できます。これは、テーブルをクラスター化したかどうかに関係なく適用されます。
@gbnが指摘したように、ヒープを圧縮する簡単な方法はありません。ただし、非常に一般的なケースである、時間の経過とともにテーブルが徐々に増加する場合、削除によって解放されたスペースが新しいデータで満たされるため、無駄はほとんどありません。
私が見たいくつかのヒープとクラスター化されたテーブルの議論は、インデックスのないヒープは常にテーブルスキャンを必要とするという点でクラスター化されたテーブルよりも劣るという奇妙なストローマンの議論をしています。これは確かに当てはまりますが、より意味のある比較は、「大規模な適切にインデックス化されたクラスター化テーブル」と「大規模な適切にインデックス化されたヒープ」です。テーブルが非常に小さい場合、または常にテーブルスキャンを実行する場合は、クラスター化してもしなくてもかまいません。
クラスター化されたテーブルの各インデックスはクラスター化インデックスを参照するため、実際にはすべてのインデックスをカバーしています。インデックス付き列とクラスタリング列を参照するクエリは、テーブル検索なしでインデックススキャンを実行できます。クラスタリングインデックスが合成キーである場合、これは一般に価値がありませんが、とにかく取得する必要があるビジネスキーである場合、それは素晴らしい機能です。
TL; DR
私はデータウェアハウジングの専門家であり、OLTPの専門家ではありません。ファクトテーブルでは、ほとんどの場合、範囲スキャン(通常は日付フィールド)が必要になる可能性が高いフィールドでクラスタリングインデックスを使用します。ディメンションテーブルの場合、PKでクラスター化するため、ファクトテーブルに対するマージ結合のために事前に並べ替えられます。
クラスタリングインデックスを使用する理由はいくつかありますが、これらの理由のいずれも当てはまらない場合、オーバーヘッドは価値がない可能性があります。クラスター化インデックスを普遍的に使用している人々の背後には、多くの「常にこの方法で行ってきた」および「ベストプラクティスである」と思われます。両方を試してみて、あなたのデータおよびあなたの負荷と最高の作品かを参照してください。