クラスター化インデックスの選択-PKまたはFK?


11

私が持っているSQL Serverの2014台をその次のようになります。

OrderId     int           not null IDENTITY --this is the primary key column
OrderDate   datetime2     not null
CustomerId  int           not null
Description nvarchar(255) null

私のチームの一部の人々は、クラスター化インデックスをオンOrderIdにすることを提案しましたが、次の理由から、CustomerId+のOrderId方が適切な選択だと思います。

  • ほとんどすべてのクエリはWHERE CustomerId = @param、ではなく、OrderId
  • CustomerIdCustomerテーブルへの外部キーなので、CustomerId結合を高速化する必要があるクラスタ化インデックスを持つ
  • 一方でCustomerId一意ではない、追加の持つOrderIdインデックスで指定した列は、(我々が使用できる一意性を保証するUNIQUEものを2列にクラスタ化インデックスを作成するときに一意性を持っていないのオーバーヘッドを回避するために、キーワードを)
  • データが挿入されると、CustomerIdそしてOrderId決して変更、これらの行は、最初の書き込みの後に動き回ることはないので。
  • データアクセスは、デフォルトですべての列を要求するORMを介して行われるため、に基づくクエリが着信CustomerIdすると、クラスター化インデックスは追加の作業なしですべての列を提供できます。

CustomerIdOrderId最良の選択肢のようなアプローチの音は、上記に与えられましたか?それとも、OrderIdそれ自体が一意性を保証する単一の列であるため、それ自体が優れていますか?

現在、テーブルにはにクラスター化インデックスがOrderIdあり、非クラスター化インデックスがにありますが、CustomerIdカバーしていません。そのため、ORMを使用しており、すべての列が要求されているため、それらを取得するのは追加の作業です。したがって、この投稿では、CIを改善してパフォーマンスを向上させることを検討しています。

DBでのアクティビティは、約85%が読み取り、15%が書き込みです。

回答:


5

コミュニティwikiの回答

ほぼすべてのクエリの句に含まれているため、最初の列がCustomerIDである複合クラスター化インデックスキーが最適だと思いますWHERE

増分キーと比較して分割数が多い可能性があります(または、「不良」分割を回避するためにフィルファクター管理および維持している場合は、しばらくの間、ページ密度が最適ではない可能性が高くなります)。ただし、キールックアップが回避されるため、顧客のクエリの全体的なパフォーマンスは大幅に向上します。

最も重要なクエリによっては、2列目にOrderIDまたはOrderDateが最適な場合があります。

たとえば、顧客がWebサイトにログインした後に最近の注文の時系列リストを表示する場合、OrderDateは次に最適化してを最適化する必要がありますORDER BY OrderDate DESC

OrderIDをクラスター化インデックスとして選択し、CustomerIDに非クラスター化インデックスを指定した場合でも、非クラスター化インデックスだけで分割と断片化が発生します。


3

このテーブルの書き込みが多すぎる場合(たとえば、それINSERTに対するステートメントではなく、より多くのステートメントが発生SELECTしている場合)は、wikiの回答に同意しません。

複合クラスター化キーの最初の列としてCustomerIDを選択すると、多数の中間ページ分割が生成されます。うまくいけば、既存の顧客がたくさんあり、常に多くの新しい顧客を獲得できます。顧客が(願わくば)ビジネスが成長し続けるにつれて複数の注文を行うので、このアプローチは、書き込みだけでなく読み取りでもパフォーマンスを低下させるかなりの量の中間ページ分割を示します。また、ホワイトスペースが多く含まれている可能性があります(つまり、ストレージとメモリの浪費です)。

CustomerIDが複合クラスター化インデックスの先頭列であると思われる場合は、FILLFACTORこのテーブルのすべてのインデックスを調整することで、ページ中央の分割の影響を減らすことができます。これにより、テーブル/インデックスのサイズが大きくなるため、ページ分割の量が減少します。この方法を使用する場合は、値を80にしてテストし、分析によってページ中央の分割が依然としてパフォーマンスを低下させていることが判明した場合は減らすことをお勧めします。

私の提案はOrderIdを使用することです。OrderIDは当然シーケンシャルであり、テーブルの増加に伴って適切であり、期待されるエンドページ分割をさらに生成する必要があります。さらに、この方法は、OrderDate列をパーティションキーとして使用することを選択した場合、テーブルパーティションでより効果的に機能します。CustomerIDフィールドを常に使用するクエリについては、それらのクエリを処理する非クラスター化インデックスを作成します。このインデックスはFILLFACTOR、上記で説明した中間ページ分割の影響を受けるため、適切に定義する必要がありますが、クラスター化インデックスに対して分割が発生していた場合と比較して、全体としてそれほど悪くはありません。

DBでのアクティビティは、約85%が読み取り、15%が書き込みです。

CustomerID+ OrderID(および分割なしで成長できるようにfillfactorを指定する)は、その評価が当てはまる場合はおそらくより優れています。ただ、作る確かな評価が正確であること。テストテストテスト。


1
最後の(または唯一の)顧客の注文をページに挿入することは、「中間ページ分割」ではないことに注意してください。したがって、顧客ごとの注文数が多い場合、または行の幅が大きい場合は、「中間ページ分割」を必要とする注文挿入が少なくなります。
デビッドブラウン-マイクロソフト2017年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.