通常、GUID を主キーとして使用するデータベースに取り組んでいます。
既定では、SQL Server はクラスター化インデックスを主キー列に配置します。これは GUID 列のばかげた考えであり、非クラスター化インデックスの方が優れていることは理解しています。
どう思いますか? すべてのクラスター化インデックスを取り除き、それらを非クラスター化インデックスに置き換える必要がありますか?
SQL のパフォーマンス チューナーがこれを推奨事項として提供しないのはなぜですか?
通常、GUID を主キーとして使用するデータベースに取り組んでいます。
既定では、SQL Server はクラスター化インデックスを主キー列に配置します。これは GUID 列のばかげた考えであり、非クラスター化インデックスの方が優れていることは理解しています。
どう思いますか? すべてのクラスター化インデックスを取り除き、それらを非クラスター化インデックスに置き換える必要がありますか?
SQL のパフォーマンス チューナーがこれを推奨事項として提供しないのはなぜですか?
クラスター化インデックスを使用する大きな理由は、特定の列の値の範囲の行を頻繁に取得する場合です。データはその順序で物理的に配置されているため、行を非常に効率的に抽出できます。
GUID のようなものは、主キーには優れていますが、挿入には追加のコストがかかり、選択には目に見えるメリットがないため、パフォーマンスに悪影響を与える可能性があります。
はい、GUID でインデックスをクラスター化しないでください。
推奨として提供されない理由については、チューナーがこの事実を認識していることをお勧めします.
ほとんどの場合、データベース内のすべてのテーブルにクラスター化インデックスを作成する必要があります。テーブルにクラスター化インデックスがない場合、それは「ヒープ」と呼ばれるものであり、ほとんどの種類の一般的なクエリのパフォーマンスは、クラスター化インデックス テーブルよりもヒープの方が低くなります。
クラスター化インデックスを確立する必要があるフィールドは、テーブル自体と、テーブルに対するクエリの予想される使用パターンによって異なります。ほとんどの場合、クラスター化インデックスを一意の列または列の組み合わせ (代替キー) に配置する必要があります。そうでない場合、SQL は一意の値を末尾に追加します。とにかく選択したフィールド。テーブルに複数のレコードを選択またはフィルター処理するためにクエリで頻繁に使用される 1 つまたは複数の列がある場合 (たとえば、テーブルに販売トランザクションが含まれていて、アプリケーションが製品 ID ごとに販売トランザクションを頻繁に要求する場合、またはさらに良い場合は、請求書の詳細テーブル。ほとんどの場合、特定の請求書のすべての詳細レコードを取得します。
これらの列は、クラスター化インデックスの候補です。クラスター化インデックスの列の順序は重要です。インデックスで定義された最初の列は、予想されるクエリで最初に選択またはフィルター処理される列である必要があります。
このすべての理由は、データベース インデックスの内部構造を理解することに基づいています。これらのインデックスは、バランス ツリー (B ツリー) インデックスと呼ばれます。二分木に似ていますが、ツリー内の各ノードは、2 つではなく、任意の数のエントリ (および子ノード) を持つことができます。クラスター化インデックスの違いは、クラスター化インデックスのリーフ ノードが、テーブル自体の実際の物理ディスク データ ページであることです。一方、非クラスター化インデックスのリーフ ノードは、テーブルのデータ ページを単に "ポイント" します。
したがって、テーブルにクラスター化されたインデックスがある場合、テーブルのデータ ページはそのインデックスのリーフ レベルであり、それぞれがインデックス順で前のページと次のページへのポインターを持ちます (それらは二重リンク リストを形成します)。 .
したがって、クエリがクラスター化インデックスと同じ順序の行の範囲を要求する場合...プロセッサは、データの開始ページを見つけるためにインデックスを 1 回 (または 2 回) 走査するだけで済みます。必要なすべてのデータ ページを読み取るまで、次のページと次のページに移動するリンク リスト ポインター。
非クラスター化インデックスの場合、取得する行ごとに 1 回インデックスをトラバースする必要があります...
注: 編集
Guid キー列のシーケンシャルの問題に対処するには、SQL2k5 には NEWSEQUENTIALID() があり、実際には「古い」シーケンシャルな方法で Guid を生成することに注意してください。
または、クライアント側コードに実装されている Jimmy Nielsens COMB GUID アルゴリズムを調べることができます。
GUID フィールドのクラスター化インデックスの問題は、GUID がランダムであるため、新しいレコードが挿入されると、テーブルの中央にレコードを挿入するためにディスク上のデータの大部分を移動する必要があることです。
ただし、整数ベースのクラスター化インデックスでは、整数は通常 ( IDENTITY
spec のように) 連続しているため、最後に追加されるだけで、データを移動する必要はありません。
一方、クラスター化されたインデックスは、GUID では常に悪いわけではありません...それはすべて、アプリケーションのニーズに依存します。迅速に記録できるようにする必要がある場合SELECT
は、クラスター化インデックスを使用してください...INSERT
速度は低下しますが、SELECT
速度は向上します。
通常、GUID でクラスタリングすることはお勧めできませんが、状況によっては、非クラスター化インデックスでも GUID が断片化を引き起こす可能性があることに注意してください。
SQL Server 2005 を使用している場合、newsequentialid()関数は連続した GUID を生成することに注意してください。これにより、断片化の問題を防ぐことができます。
決定を下す前に、次のような SQL クエリを使用して断片化を測定することをお勧めします (非 ANSI 構文を許してください)。
SELECT OBJECT_NAME (ips.[object_id]) AS 'Object Name',
si.name AS 'Index Name',
ROUND (ips.avg_fragmentation_in_percent, 2) AS 'Fragmentation',
ips.page_count AS 'Pages',
ROUND (ips.avg_page_space_used_in_percent, 2) AS 'Page Density'
FROM sys.dm_db_index_physical_stats
(DB_ID ('MyDatabase'), NULL, NULL, NULL, 'DETAILED') ips
CROSS APPLY sys.indexes si
WHERE si.object_id = ips.object_id
AND si.index_id = ips.index_id
AND ips.index_level = 0;
NewId() を使用している場合は、NewSequentialId() に切り替えることができます。これは、挿入パフォーマンスに役立つはずです。
はい、ランダムな値にクラスター化インデックスを設定しても意味がありません。
おそらく、データベースのどこかにクラスター化インデックスが必要です。たとえば、"Author" テーブルと "Author" への外部キーを持つ "Book" テーブルがあり、アプリケーションに "select ... from Book where AuthorId = .. 」なら、あなたは一組の本を読んでいることになります。それらの本がディスク上で物理的に隣り合っていると、ディスクヘッドがセクターからセクターへと跳ね返り、その著者のすべての本を収集する必要がなくなります。
そのため、アプリケーション、つまりデータベースにクエリを実行する方法について考える必要があります。
変更を行います。
そして、あなたが決して知らないので、テストしてください...
ほとんどの人が言及しているように、クラスター化インデックスでランダムな識別子を使用しないでください。クラスター化の利点は得られません。実際には、遅延が増加します。それらをすべて取り除くことは確かなアドバイスです。また、マルチマスター レプリケーション シナリオでは、newsequentialid() が非常に問題になる可能性があることにも注意してください。データベース A と B の両方がレプリケーションの前に newsequentialid() を呼び出すと、競合が発生します。
はい、上記の Galwegian の理由から、GUID プライマリ キーのクラスター化インデックスを削除する必要があります。アプリケーションでこれを行いました。
大量の挿入を行っているか、PK による非常に迅速な検索が必要かによって異なります。