PKインデックスの列の順序は重要ですか?


33

同じ基本構造を持ついくつかの非常に大きなテーブルがあります。それぞれにRowNumber (bigint)DataDate (date)列があります。データは毎晩SQLBulkImportを使用してロードされ、「新しい」データはロードされません-その履歴レコード(エンタープライズではなくSQL標準なので、パーティショニングはありません)。

データの各ビットは他のシステムに結び付ける必要があり、各RowNumber/DataDate組み合わせは一意であるため、それが私の主キーです。

SSMS Table DesignerでPKを定義した方法により、RowNumber最初とDataDate2番目にリストされていることに気付きました。

また、私の断片化は常に非常に高い〜99%であることに気付きます。

今、それぞれDataDateが一度しか表示されないため、インデクサーが毎日ページに追加することを期待していますが、実際にはRowNumber最初に基づいてインデックス付けされているので、他のすべてを移動する必要がありますか?


RownumberID列ではなく、外部システムによって(悲しいことに)生成されたintです。それぞれの開始時にリセットされますDataDate

サンプルデータ

RowNumber | DataDate | a | b | c..... 
   1      |2013-08-01| x | y | z 
   2      |2013-08-01| x | y | z 
...
   1      |2013-08-02| x | y | z 
   2      |2013-08-02| x | y | z 
...

データはロードごとにRowNumber順番にロードされDataDateます。

インポートプロセスはbcpです-一時テーブルにロードして、そこから順番に選択してみました(ORDER BY RowNumber, DataDate)が、依然として高い断片化が発生しています。

回答:


50

PKインデックスの列の順序は重要ですか?

はい、そうです。

既定では、主キー制約は一意のクラスター化インデックスによってSQL Serverに適用されます。クラスタ化インデックスは、テーブル内の行の論理的な順序を定義します。bツリーインデックスの上位レベルを表すために追加のインデックスページがいくつか追加される場合がありますが、クラスター化インデックスの最下位(リーフ)レベルは、単にデータ自体の論理的な順序です。

これを明確にするために、ページ上の行は必ずしもクラスター化インデックスキーの順序で物理的に格納されるとは限りません。ページ内には、各行へのポインタを格納する独立した間接構造があります。この構造は、クラスター化インデックスキーによって並べ替えられます。また、各ページには、クラスター化インデックスキーの順序で同じレベルにある前のページと次のページへのポインターがあります。

のクラスター化された主キーで(RowNumber, DataDate)は、行が最初に論理的に並べ替えられRowNumber、次に論理的に並べ替えられます。つまり、DataDateすべての行RowNumber = 1が論理的にグループ化され、次に行が続きRowNumber = 2ます。

新しいデータ(RowNumbers1〜n)を追加すると、新しい行は論理的に既存のページ内に属します。そのため、SQL Serverはスペースを確保するためにページを分割する多くの作業を行う必要があります。このすべてのアクティビティは、多くの余分な作業(変更のログ記録を含む)を生成します。

分割ページも約50%の空で始まります。そのため、過剰な分割により、ページ密度が低くなる可能性があります(ページごとに最適な行よりも少ない行)。ディスクからの読み取りに悪い知らせがあるだけでなく(低密度=読み取るページが多い)、低密度のページはキャッシュ時にメモリのスペースをより多く使用します。

クラスタ化インデックスを(DataDate, RowNumber)に変更すると、新しいデータ(おそらく、DataDates現在格納されているデータよりも大きい)が、新しいページのクラスタ化インデックスの論理的な最後に追加されます。これにより、ページ分割の不要なオーバーヘッドが削除され、ロード時間が短縮されます。データの断片化が少ないということは、先読みアクティビティ(進行中のクエリに必要になる直前にディスクからページを読み取る)がより効率的になることも意味します。

何もない場合は、あなたのクエリは、はるかに検索する可能性があるDataDate以上RowNumber。上のクラスター化インデックス(DataDate, RowNumber)は、インデックスシークをサポートしますDataDate(その後RowNumber)。既存の配置は、シークオンのみをサポートしますRowNumber(その場合のみ、おそらくオンDataDate)。DataDate主キーが変更されると、既存の非クラスター化インデックスを削除できる場合があります。クラスター化インデックスは、置き換えられる非クラスター化インデックスよりも幅が広いため、テストしてパフォーマンスが許容範囲内にあることを確認する必要があります。

で新しいデータをインポートするときにbcp、インポートファイル内のデータがクラスター化インデックスキーでソートされ(理想的には(DataDate, RowNumber)、bcpオプションを指定するとパフォーマンスが向上する可能性があります。

-h "ORDER(DataDate,RowNumber), TABLOCK"

最高のデータ読み込みパフォーマンスを得るために、最小限のログ記録の挿入を達成しようとするかもしれません。詳細については、以下を参照してください。


4
優れた答え-私は今やるべきこととその理由を知っています。私はそう思っていましたが、そうではありませんでした!ありがとうございました。
BlueChippy

テストのためにローカルのSQL ServerにDBを取得するためにLOOOOONGを取得しました。インデックスのロードを変更する前に45分かかりました...その後、わずか5分で完了しました!!!
BlueChippy

13

はい、順序は重要です。RowNumber(例WHERE RowNumber=1)でクエリすることは非常に疑わしいです。圧倒的に時系列はdate(WHERE DataDate BEWEEN @start AND @end)によって質問されます、そして、そのような質問はによってクラスタ化された組織を必要とするでしょうDataDate

断片化は、一般に赤ニシンです。ここでは、断片化を減らすことを目標にするべきではありませんが、クエリを適切に編成する必要があります。さらに断片化を減らすことは良い考えですが、それ自体は目標ではありません。ワークロードに一致する適切に編成されたデータモデルがあり(クエリが適切にカバーされている)パフォーマンスに影響するフラグメンテーションを示す測定値がある場合は、それについてお話します。


また、DataDateには非クラスター化インデックスがあります。これは、多くのWHERE場合、クエリの句です。
BlueChippy

1
列の順序が重要な場合、誤った順序の影響でI / Oが増加しますか?私の考えは、RowNumberによる順序付けであり、したがって、DataDateに基づいている必要がありますが、毎回インデックスで多くの作業を行う必要があるということですか?
BlueChippy
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.