以前に尋ねた別の質問のテストデータベースを作成しているときに、主キーを宣言できることを思い出しました NONCLUSTERED
NONCLUSTERED
主キーではなく主キーをいつ使用しCLUSTERED
ますか?
前もって感謝します
以前に尋ねた別の質問のテストデータベースを作成しているときに、主キーを宣言できることを思い出しました NONCLUSTERED
NONCLUSTERED
主キーではなく主キーをいつ使用しCLUSTERED
ますか?
前もって感謝します
回答:
質問は「PKをいつNCにすべきか」ではなく、「クラスター化インデックスの適切なキーは何か」と尋ねるべきです。
そして、答えは本当にあなたがどのようにデータを問い合わせるかに依存します。クラスター化インデックスは、他のすべてのインデックスよりも優れています。常にすべての列が含まれるため、常にカバーされます。したがって、クラスター化インデックスを活用できるクエリは、ルックアップを使用して、投影された列や述語の一部を満たす必要はありません。
パズルのもう1つのピースは、インデックスの使用方法です。3つの典型的なパターンがあります。
そのため、予想される負荷(クエリ)を分析し、インデックスの恩恵を受ける特定のアクセスパターンを使用しているため、多数のクエリが特定のインデックスを使用することを発見した場合、そのインデックスをクラスター化インデックスとして提案するのは理にかなっています。
さらに別の要因は、クラスター化インデックスキーがすべての非クラスター化インデックスで使用されるルックアップキーであるため、広いクラスター化インデックスキーは波及効果を作成し、すべての非クラスター化インデックスを広げ、広いインデックスはより多くのページ、より多くのI / Oを意味することです、より多くのメモリ、より少ない善。
優れたクラスター化インデックスは安定しており、エンティティーの存続期間中は変化しません。クラスター化インデックスキーの値を変更すると、行を削除して挿入し直す必要があるためです。
また、ページ分割やフラグメンテーションを回避するために、(FILLFACTOR
s をいじらずに)良好なクラスター化インデックスはランダムではなく(新しく挿入された各キー値が前の値よりも大きい)順に成長します。
優れたクラスター化インデックスキーが何であるかがわかったので、プライマリキー(データモデリングの論理プロパティ)は要件に一致しますか?はいの場合、PKをクラスター化する必要があります。いいえの場合、PKはクラスター化されていません。
例として、販売ファクトテーブルを考えてみましょう。各エントリには、プライマリキーであるIDがあります。ただし、クエリの大半は日付と別の日付の間のデータを要求するため、最適なクラスター化インデックスキーはIDではなく販売日です。主キーとは異なるクラスター化インデックスを持つ別の例は、「カテゴリ」や「状態」など、非常に少数の異なる値しか持たないキーなど、非常に低い選択性キーです。左端のキーとしてこの低い選択性キーを持つクラスター化インデックスキーを持つことは、たとえば、特定の「状態」のすべてのエントリを検索する範囲スキャンのために、しばしば意味があります。(state, id)
ヒープ上の非クラスター化プライマリキーの可能性に関する最後の注意点(つまり、クラスター化インデックスがまったくない)。これは有効なシナリオである可能性があります。典型的な理由は、クラスター化インデックスに比べてヒープのバルク挿入スループットが大幅に向上するため、バルク挿入パフォーマンスが重要な場合です。
(state, id)
。この例では、「適切なクラスター化インデックスはランダムではなく順に成長します」という要件を満たしていませんか?では、それを優れたクラスター化インデックスと見なすことができますか?
クラスター化インデックスを使用する基本的な理由は、Wikipediaに記載されています。
クラスタリングは、データブロックを特定の異なる順序に変更してインデックスに一致させ、行データが順番に格納されるようにします。したがって、特定のデータベーステーブルに作成できるクラスター化インデックスは1つだけです。クラスター化インデックスは、全体的な取得速度を大幅に向上させることができますが、通常、クラスター化インデックスと同じ順序または逆の順序でデータに連続してアクセスする場合、またはアイテムの範囲が選択されている場合のみです。
私はPeopleのテーブルがあり、これらの人々にはCountry列と一意の主キーがあるとします。これは人口統計表なので、私が気にするのはこれらだけです。その国にどの国と何人のユニークな人が結びついているか。
したがって、国の列でWHEREまたはORDER BYを選択することはほとんどありません。主キーのクラスター化インデックスは役に立ちません。PKでこのデータにアクセスするのではなく、この他の列でアクセスします。テーブルには1つのクラスター化インデックスしか持てないため、PKをクラスター化として宣言すると、国でクラスター化インデックスを使用できなくなります。
さらに、クラスター化インデックスと非クラスター化インデックスに関する良い記事があります。SQLServer 6.5でクラスター化インデックスが挿入パフォーマンスの問題を引き起こしたことがわかりました(少なくともここではほとんどの人には関係ないでしょう)。
IDENTITY列にクラスター化インデックスを配置すると、挿入はすべてテーブルの最後のページで行われ、そのページは各IDENTITYの間ロックされます。大したことはありません...最後のページを望んでいる5000人の人がいない限り。次に、そのページに対して多くの競合があります
これは後のバージョンでは当てはまらないことに注意してください。
主キーがの場合はUNIQUEIDENTIFIER
、必ずであることを指定してくださいNONCLUSTERED
。クラスター化すると、すべての挿入でレコードを大量にシャッフルして、新しい行を正しい位置に挿入する必要があります。これにより、パフォーマンスが向上します。
UNIQUEIDENTIFIER
タイプも存在し、一意のキーを生成する確率は同じですが、128サイズという問題があります。
非常に一般的な例:
Customer
CustomerID
asを持つテーブルCLUSTERED PRIMARY KEY
OrderID (PK), CustomerID, OrderDate
その他の列OrderPositions
と OrderPositionID (PK), OrderId, ProductID, Amount, Price ...
もちろん、「依存する」は-ほぼ常に正しい答えですが、ほとんどのアプリケーション(BIレポートではなく)は顧客ベースで動作します(たとえば、顧客278としてWebサイトにログインし、「注文」をクリックするか、店員が顧客4569のすべての注文をリストするか、請求書ルーチンが顧客137のすべての注文をまとめます。
この場合、テーブルをクラスタ化することはあまり意味がありませんOrderID
。はい、SELECT ... WHERE OrderId = ?
注文の詳細をリストするクエリがありますが、これは通常、短くて安価な(3回の読み取り)インデックスシークになります。
一方、でOrder
テーブルをクラスタ化する場合CustomerID
、テーブルをクエリするたびに複数のキー検索を行う必要はありませんCustomerId = ?
。
CLUSTERED INDEX
常にする必要がありUNIQUE
そうでない場合はSQL Serverは、目に見えない(=使用不可)INT列を追加し、UNIQUIFIER
それはその後、いくつかの(挿入順序に依存する)ランダムなものを実際の(使用可能な)データを追加するためにはるかに理にかなって- uniquinessを確保するために。
顧客は(願わくば)複数の注文を行うため、OrderID
(通常、このために並べ替える場合)または(OrderDate
日時の場合-それ以外の場合、顧客は1日に1注文に制限されます)のいずれかを追加する必要がありますそしてCLUSTERED INDEX
、で終わる:
CREATE UNIQUE CLUSTERED INDEX IX_Orders_UQ on Orders (CustomerID, OrderID)
同じ規則がOrderPositions
テーブルに適用されます。通常、ほとんどのクエリは特定の順序ですべての位置をリストするため、OrderPositionID
as NONCLUSTERED
およびUNIQUE CLUSTERED INDEX
on を使用してPKを作成する必要がありますOrderId, OrderPositionID
。
ところで:Customer
テーブルがそのPKによってクラスター化されていることは正しいです(CustomerID
「トップレベルテーブル」であるため、通常のアプリケーションでは、ほとんどがそのCustomerIDによってクエリされます)。
Genders
またはInvoiceTypes
などの純粋なルックアップテーブルPaymentType
は、PKによってクラスター化される必要があるテーブルの別の例です(通常はGenderId
、InvoiceTypeId
またはに参加するためPaymentTypeId
)。
何らかの指標を使用して、クラスター化インデックスがクラスター化PKよりもシステム全体にとって有益であると見なされる場合。テーブルに存在できるクラスター化インデックスは1つだけです。
パフォーマンスの尺度の例は、単一クエリ時間(速度)、テーブルに対する合計クエリ時間の統合(効率)、およびクラスター化(サイズと同様のパフォーマンスを達成するために非常に大きな非クラスター化インデックスに多くのinclude列を追加する必要がある) )。
これは、一意ではないインデックス、nullを含むインデックス(PKで許可されていない)を使用してデータが一般的に取得された場合、またはPKが二次的な理由(レプリケーションや監査証跡レコードの識別など)で追加された場合に発生します。